Merge remote-tracking branch 'origin/master' into step
This commit is contained in:
commit
358238f745
|
@ -1036,7 +1036,7 @@ bool Application::activateWorkbench(const char* name)
|
||||||
}
|
}
|
||||||
|
|
||||||
Base::Console().Error("%s\n", (const char*)msg.toLatin1());
|
Base::Console().Error("%s\n", (const char*)msg.toLatin1());
|
||||||
Base::Console().Log("%s\n", e.getStackTrace().c_str());
|
Base::Console().Error("%s\n", e.getStackTrace().c_str());
|
||||||
if (!d->startingUp) {
|
if (!d->startingUp) {
|
||||||
wc.restoreCursor();
|
wc.restoreCursor();
|
||||||
QMessageBox::critical(getMainWindow(), QObject::tr("Workbench failure"),
|
QMessageBox::critical(getMainWindow(), QObject::tr("Workbench failure"),
|
||||||
|
@ -1279,10 +1279,9 @@ typedef void (*_qt_msg_handler_old)(QtMsgType type, const char *msg);
|
||||||
_qt_msg_handler_old old_qtmsg_handler = 0;
|
_qt_msg_handler_old old_qtmsg_handler = 0;
|
||||||
|
|
||||||
#if QT_VERSION >= 0x050000
|
#if QT_VERSION >= 0x050000
|
||||||
void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &qmsg)
|
void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||||
{
|
{
|
||||||
Q_UNUSED(context);
|
Q_UNUSED(context);
|
||||||
const QChar *msg = qmsg.unicode();
|
|
||||||
#ifdef FC_DEBUG
|
#ifdef FC_DEBUG
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -1290,26 +1289,26 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt
|
||||||
case QtInfoMsg:
|
case QtInfoMsg:
|
||||||
#endif
|
#endif
|
||||||
case QtDebugMsg:
|
case QtDebugMsg:
|
||||||
Base::Console().Message("%s\n", msg);
|
Base::Console().Message("%s\n", msg.toUtf8().constData());
|
||||||
break;
|
break;
|
||||||
case QtWarningMsg:
|
case QtWarningMsg:
|
||||||
Base::Console().Warning("%s\n", msg);
|
Base::Console().Warning("%s\n", msg.toUtf8().constData());
|
||||||
break;
|
break;
|
||||||
case QtCriticalMsg:
|
case QtCriticalMsg:
|
||||||
Base::Console().Error("%s\n", msg);
|
Base::Console().Error("%s\n", msg.toUtf8().constData());
|
||||||
break;
|
break;
|
||||||
case QtFatalMsg:
|
case QtFatalMsg:
|
||||||
Base::Console().Error("%s\n", msg);
|
Base::Console().Error("%s\n", msg.toUtf8().constData());
|
||||||
abort(); // deliberately core dump
|
abort(); // deliberately core dump
|
||||||
}
|
}
|
||||||
#ifdef FC_OS_WIN32
|
#ifdef FC_OS_WIN32
|
||||||
if (old_qtmsg_handler)
|
if (old_qtmsg_handler)
|
||||||
(*old_qtmsg_handler)(type, context, qmsg);
|
(*old_qtmsg_handler)(type, context, msg);
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
// do not stress user with Qt internals but write to log file if enabled
|
// do not stress user with Qt internals but write to log file if enabled
|
||||||
Q_UNUSED(type);
|
Q_UNUSED(type);
|
||||||
Base::Console().Log("%s\n", msg);
|
Base::Console().Log("%s\n", msg.toUtf8().constData());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
void pause();
|
void pause();
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void readClient();
|
void readClient();
|
||||||
void discardClient();
|
void discardClient();
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,7 @@ void TaskHeader::leaveEvent ( QEvent * /*event*/ )
|
||||||
void TaskHeader::fold()
|
void TaskHeader::fold()
|
||||||
{
|
{
|
||||||
if (myExpandable) {
|
if (myExpandable) {
|
||||||
emit activated();
|
Q_EMIT activated();
|
||||||
// Toggling the 'm_fold' member here may lead to inconsistencies with its ActionGroup.
|
// Toggling the 'm_fold' member here may lead to inconsistencies with its ActionGroup.
|
||||||
// Thus, the method setFold() was added and called from ActionGroup when required.
|
// Thus, the method setFold() was added and called from ActionGroup when required.
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -254,7 +254,7 @@ void TaskHeader::changeIcons()
|
||||||
void TaskHeader::mouseReleaseEvent ( QMouseEvent * event )
|
void TaskHeader::mouseReleaseEvent ( QMouseEvent * event )
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
emit activated();
|
Q_EMIT activated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
|
|
||||||
QMenu * getMenu(void) const;
|
QMenu * getMenu(void) const;
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void changeRenderMode(QAction * action);
|
void changeRenderMode(QAction * action);
|
||||||
void changeStereoMode(QAction * action);
|
void changeStereoMode(QAction * action);
|
||||||
void changeTransparencyType(QAction * action);
|
void changeTransparencyType(QAction * action);
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
SensorManager(void);
|
SensorManager(void);
|
||||||
~SensorManager();
|
~SensorManager();
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void idleTimeout(void);
|
void idleTimeout(void);
|
||||||
void delayTimeout(void);
|
void delayTimeout(void);
|
||||||
void timerQueueTimeout(void);
|
void timerQueueTimeout(void);
|
||||||
|
|
|
@ -70,7 +70,7 @@ SignalThread::run(void)
|
||||||
// just wait, and trigger every time we receive a signal
|
// just wait, and trigger every time we receive a signal
|
||||||
this->waitcond.wait(&this->mutex);
|
this->waitcond.wait(&this->mutex);
|
||||||
if (!this->isstopped) {
|
if (!this->isstopped) {
|
||||||
emit triggerSignal();
|
Q_EMIT triggerSignal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,10 +162,10 @@ void iisIconLabel::mousePressEvent ( QMouseEvent * event )
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
m_pressed = true;
|
m_pressed = true;
|
||||||
emit pressed();
|
Q_EMIT pressed();
|
||||||
} else
|
} else
|
||||||
if (event->button() == Qt::RightButton)
|
if (event->button() == Qt::RightButton)
|
||||||
emit contextMenu();
|
Q_EMIT contextMenu();
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -174,11 +174,11 @@ void iisIconLabel::mouseReleaseEvent ( QMouseEvent * event )
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
m_pressed = false;
|
m_pressed = false;
|
||||||
emit released();
|
Q_EMIT released();
|
||||||
|
|
||||||
if (rect().contains( event->pos() )) {
|
if (rect().contains( event->pos() )) {
|
||||||
emit clicked();
|
Q_EMIT clicked();
|
||||||
emit activated();
|
Q_EMIT activated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ void iisIconLabel::keyPressEvent ( QKeyEvent * event )
|
||||||
switch (event->key()) {
|
switch (event->key()) {
|
||||||
case Qt::Key_Space:
|
case Qt::Key_Space:
|
||||||
case Qt::Key_Return:
|
case Qt::Key_Return:
|
||||||
emit activated();
|
Q_EMIT activated();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:;
|
default:;
|
||||||
|
|
|
@ -165,7 +165,7 @@ void iisTaskHeader::leaveEvent ( QEvent * /*event*/ )
|
||||||
void iisTaskHeader::fold()
|
void iisTaskHeader::fold()
|
||||||
{
|
{
|
||||||
if (myExpandable) {
|
if (myExpandable) {
|
||||||
emit activated();
|
Q_EMIT activated();
|
||||||
|
|
||||||
m_fold = !m_fold;
|
m_fold = !m_fold;
|
||||||
changeIcons();
|
changeIcons();
|
||||||
|
@ -195,7 +195,7 @@ void iisTaskHeader::changeIcons()
|
||||||
void iisTaskHeader::mouseReleaseEvent ( QMouseEvent * event )
|
void iisTaskHeader::mouseReleaseEvent ( QMouseEvent * event )
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
emit activated();
|
Q_EMIT activated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -222,46 +222,6 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_18">
|
|
||||||
<property name="text">
|
|
||||||
<string>Dimensions precision level</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="Gui::PrefSpinBox" name="gui::prefspinbox_5">
|
|
||||||
<property name="maximum">
|
|
||||||
<number>8</number>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<number>2</number>
|
|
||||||
</property>
|
|
||||||
<property name="prefEntry" stdset="0">
|
|
||||||
<cstring>dimPrecision</cstring>
|
|
||||||
</property>
|
|
||||||
<property name="prefPath" stdset="0">
|
|
||||||
<cstring>Mod/Draft</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>522</width>
|
<width>522</width>
|
||||||
<height>462</height>
|
<height>473</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -153,6 +153,46 @@ such as "Arial:Bold"</string>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_19">
|
||||||
|
<property name="text">
|
||||||
|
<string>Number of decimals</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Gui::PrefSpinBox" name="gui::prefspinbox_5">
|
||||||
|
<property name="maximum">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="prefEntry" stdset="0">
|
||||||
|
<cstring>dimPrecision</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="prefPath" stdset="0">
|
||||||
|
<cstring>Mod/Draft</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
|
@ -364,7 +404,7 @@ such as "Arial:Bold"</string>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser" native="true">
|
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>300</width>
|
<width>300</width>
|
||||||
|
@ -405,6 +445,21 @@ such as "Arial:Bold"</string>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>Gui::FileChooser</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>Gui/FileDialog.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>Gui::PrefFileChooser</class>
|
||||||
|
<extends>Gui::FileChooser</extends>
|
||||||
|
<header>Gui/PrefWidgets.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>Gui::PrefSpinBox</class>
|
||||||
|
<extends>QSpinBox</extends>
|
||||||
|
<header>Gui/PrefWidgets.h</header>
|
||||||
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>Gui::PrefCheckBox</class>
|
<class>Gui::PrefCheckBox</class>
|
||||||
<extends>QCheckBox</extends>
|
<extends>QCheckBox</extends>
|
||||||
|
@ -425,16 +480,6 @@ such as "Arial:Bold"</string>
|
||||||
<extends>QDoubleSpinBox</extends>
|
<extends>QDoubleSpinBox</extends>
|
||||||
<header>Gui/PrefWidgets.h</header>
|
<header>Gui/PrefWidgets.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
|
||||||
<class>Gui::FileChooser</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>Gui/FileDialog.h</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>Gui::PrefFileChooser</class>
|
|
||||||
<extends>Gui::FileChooser</extends>
|
|
||||||
<header>Gui/PrefWidgets.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|
|
@ -776,6 +776,8 @@ non-parametric curve"""
|
||||||
warn('polygon fallback on %s' %spline)
|
warn('polygon fallback on %s' %spline)
|
||||||
return drawSplineIterpolation(controlpoints,closed=closed,\
|
return drawSplineIterpolation(controlpoints,closed=closed,\
|
||||||
forceShape=forceShape,alwaysDiscretize=True)
|
forceShape=forceShape,alwaysDiscretize=True)
|
||||||
|
if fitpoints and not(controlpoints):
|
||||||
|
return drawSplineIterpolation(fitpoints,closed=closed,forceShape=forceShape)
|
||||||
try:
|
try:
|
||||||
bspline=Part.BSplineCurve()
|
bspline=Part.BSplineCurve()
|
||||||
bspline.buildFromPolesMultsKnots(poles=controlpoints,mults=multvector,\
|
bspline.buildFromPolesMultsKnots(poles=controlpoints,mults=multvector,\
|
||||||
|
|
|
@ -71,6 +71,7 @@ SET(FemScripts_SRCS
|
||||||
_CommandMaterial.py
|
_CommandMaterial.py
|
||||||
_CommandMeshGmshFromShape.py
|
_CommandMeshGmshFromShape.py
|
||||||
_CommandMeshNetgenFromShape.py
|
_CommandMeshNetgenFromShape.py
|
||||||
|
_CommandMeshGroup.py
|
||||||
_CommandMeshRegion.py
|
_CommandMeshRegion.py
|
||||||
_CommandPrintMeshInfo.py
|
_CommandPrintMeshInfo.py
|
||||||
_CommandPurgeResults.py
|
_CommandPurgeResults.py
|
||||||
|
@ -83,6 +84,7 @@ SET(FemScripts_SRCS
|
||||||
_FemConstraintSelfWeight.py
|
_FemConstraintSelfWeight.py
|
||||||
_FemMaterialMechanicalNonlinear.py
|
_FemMaterialMechanicalNonlinear.py
|
||||||
_FemMeshGmsh.py
|
_FemMeshGmsh.py
|
||||||
|
_FemMeshGroup.py
|
||||||
_FemMeshRegion.py
|
_FemMeshRegion.py
|
||||||
_FemShellThickness.py
|
_FemShellThickness.py
|
||||||
_FemSolverCalculix.py
|
_FemSolverCalculix.py
|
||||||
|
@ -90,6 +92,7 @@ SET(FemScripts_SRCS
|
||||||
_FemMaterial.py
|
_FemMaterial.py
|
||||||
_TaskPanelFemBeamSection.py
|
_TaskPanelFemBeamSection.py
|
||||||
_TaskPanelFemMeshGmsh.py
|
_TaskPanelFemMeshGmsh.py
|
||||||
|
_TaskPanelFemMeshGroup.py
|
||||||
_TaskPanelFemMeshRegion.py
|
_TaskPanelFemMeshRegion.py
|
||||||
_TaskPanelFemShellThickness.py
|
_TaskPanelFemShellThickness.py
|
||||||
_TaskPanelFemSolverCalculix.py
|
_TaskPanelFemSolverCalculix.py
|
||||||
|
@ -99,6 +102,7 @@ SET(FemScripts_SRCS
|
||||||
_ViewProviderFemConstraintSelfWeight.py
|
_ViewProviderFemConstraintSelfWeight.py
|
||||||
_ViewProviderFemMaterialMechanicalNonlinear.py
|
_ViewProviderFemMaterialMechanicalNonlinear.py
|
||||||
_ViewProviderFemMeshGmsh.py
|
_ViewProviderFemMeshGmsh.py
|
||||||
|
_ViewProviderFemMeshGroup.py
|
||||||
_ViewProviderFemMeshRegion.py
|
_ViewProviderFemMeshRegion.py
|
||||||
_ViewProviderFemShellThickness.py
|
_ViewProviderFemShellThickness.py
|
||||||
_ViewProviderFemSolverCalculix.py
|
_ViewProviderFemSolverCalculix.py
|
||||||
|
@ -122,6 +126,7 @@ SET(FemScripts_SRCS
|
||||||
FemMaterialMechanicalNonlinear.py
|
FemMaterialMechanicalNonlinear.py
|
||||||
FemMesh2Mesh.py
|
FemMesh2Mesh.py
|
||||||
FemMeshGmsh.py
|
FemMeshGmsh.py
|
||||||
|
FemMeshGroup.py
|
||||||
FemMeshRegion.py
|
FemMeshRegion.py
|
||||||
FemMeshTools.py
|
FemMeshTools.py
|
||||||
FemShellThickness.py
|
FemShellThickness.py
|
||||||
|
@ -136,6 +141,7 @@ SET(FemScripts_SRCS
|
||||||
z88DispReader.py
|
z88DispReader.py
|
||||||
TaskPanelFemBeamSection.ui
|
TaskPanelFemBeamSection.ui
|
||||||
TaskPanelFemMeshGmsh.ui
|
TaskPanelFemMeshGmsh.ui
|
||||||
|
TaskPanelFemMeshGroup.ui
|
||||||
TaskPanelFemMeshRegion.ui
|
TaskPanelFemMeshRegion.ui
|
||||||
TaskPanelFemShellThickness.ui
|
TaskPanelFemShellThickness.ui
|
||||||
TaskPanelFemSolverCalculix.ui
|
TaskPanelFemSolverCalculix.ui
|
||||||
|
|
|
@ -42,6 +42,8 @@ FemResultObject::FemResultObject()
|
||||||
ADD_PROPERTY_TYPE(Stats,(0), "Fem",Prop_None,"Statistics of the results");
|
ADD_PROPERTY_TYPE(Stats,(0), "Fem",Prop_None,"Statistics of the results");
|
||||||
ADD_PROPERTY_TYPE(DisplacementVectors,(), "Fem",Prop_None,"List of displacement vectors");
|
ADD_PROPERTY_TYPE(DisplacementVectors,(), "Fem",Prop_None,"List of displacement vectors");
|
||||||
ADD_PROPERTY_TYPE(DisplacementLengths,(0), "Fem",Prop_None,"List of displacement lengths");
|
ADD_PROPERTY_TYPE(DisplacementLengths,(0), "Fem",Prop_None,"List of displacement lengths");
|
||||||
|
ADD_PROPERTY_TYPE(StressVectors,(), "Fem",Prop_None,"List of Stress vectors");
|
||||||
|
ADD_PROPERTY_TYPE(StrainVectors,(), "Fem",Prop_None,"List of Strain vectors");
|
||||||
ADD_PROPERTY_TYPE(StressValues,(0), "Fem",Prop_None,"List of Von Misses stress values");
|
ADD_PROPERTY_TYPE(StressValues,(0), "Fem",Prop_None,"List of Von Misses stress values");
|
||||||
ADD_PROPERTY_TYPE(PrincipalMax,(0), "Fem",Prop_None,"List of First Principal (Max) stress values");
|
ADD_PROPERTY_TYPE(PrincipalMax,(0), "Fem",Prop_None,"List of First Principal (Max) stress values");
|
||||||
ADD_PROPERTY_TYPE(PrincipalMed,(0), "Fem",Prop_None,"List of Second Principal (Med) stress values");
|
ADD_PROPERTY_TYPE(PrincipalMed,(0), "Fem",Prop_None,"List of Second Principal (Med) stress values");
|
||||||
|
@ -59,6 +61,8 @@ FemResultObject::FemResultObject()
|
||||||
Stats.setStatus(App::Property::ReadOnly, true);
|
Stats.setStatus(App::Property::ReadOnly, true);
|
||||||
DisplacementVectors.setStatus(App::Property::ReadOnly, true);
|
DisplacementVectors.setStatus(App::Property::ReadOnly, true);
|
||||||
DisplacementLengths.setStatus(App::Property::ReadOnly, true);
|
DisplacementLengths.setStatus(App::Property::ReadOnly, true);
|
||||||
|
StressVectors.setStatus(App::Property::ReadOnly, true);
|
||||||
|
StrainVectors.setStatus(App::Property::ReadOnly, true);
|
||||||
StressValues.setStatus(App::Property::ReadOnly, true);
|
StressValues.setStatus(App::Property::ReadOnly, true);
|
||||||
PrincipalMax.setStatus(App::Property::ReadOnly, true);
|
PrincipalMax.setStatus(App::Property::ReadOnly, true);
|
||||||
PrincipalMed.setStatus(App::Property::ReadOnly, true);
|
PrincipalMed.setStatus(App::Property::ReadOnly, true);
|
||||||
|
|
|
@ -49,8 +49,12 @@ public:
|
||||||
App::PropertyFloatList Stats;
|
App::PropertyFloatList Stats;
|
||||||
/// Displacement vectors of analysis
|
/// Displacement vectors of analysis
|
||||||
App::PropertyVectorList DisplacementVectors;
|
App::PropertyVectorList DisplacementVectors;
|
||||||
/// Lengths of displacement vestors of analysis
|
/// Lengths of displacement vectors of analysis
|
||||||
App::PropertyFloatList DisplacementLengths;
|
App::PropertyFloatList DisplacementLengths;
|
||||||
|
/// Stress vectors of analysis
|
||||||
|
App::PropertyVectorList StressVectors;
|
||||||
|
/// Strain vectors of analysis
|
||||||
|
App::PropertyVectorList StrainVectors;
|
||||||
/// Von Mises Stress values of analysis
|
/// Von Mises Stress values of analysis
|
||||||
App::PropertyFloatList StressValues;
|
App::PropertyFloatList StressValues;
|
||||||
/// First principal Stress values of analysis
|
/// First principal Stress values of analysis
|
||||||
|
|
|
@ -760,6 +760,7 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
||||||
const FemResultObject* res = static_cast<const FemResultObject*>(obj);
|
const FemResultObject* res = static_cast<const FemResultObject*>(obj);
|
||||||
if(!res->StressValues.getValues().empty()) {
|
if(!res->StressValues.getValues().empty()) {
|
||||||
const std::vector<double>& vec = res->StressValues.getValues();
|
const std::vector<double>& vec = res->StressValues.getValues();
|
||||||
|
if (vec.size()>1) {
|
||||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||||
data->SetNumberOfValues(vec.size());
|
data->SetNumberOfValues(vec.size());
|
||||||
data->SetName("Von Mises stress");
|
data->SetName("Von Mises stress");
|
||||||
|
@ -768,10 +769,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
||||||
data->SetValue(i, vec[i]);
|
data->SetValue(i, vec[i]);
|
||||||
|
|
||||||
grid->GetPointData()->AddArray(data);
|
grid->GetPointData()->AddArray(data);
|
||||||
}
|
}}
|
||||||
|
|
||||||
if(!res->StressValues.getValues().empty()) {
|
if(!res->MaxShear.getValues().empty()) {
|
||||||
const std::vector<double>& vec = res->MaxShear.getValues();
|
const std::vector<double>& vec = res->MaxShear.getValues();
|
||||||
|
if (vec.size()>1) {
|
||||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||||
data->SetNumberOfValues(vec.size());
|
data->SetNumberOfValues(vec.size());
|
||||||
data->SetName("Max shear stress (Tresca)");
|
data->SetName("Max shear stress (Tresca)");
|
||||||
|
@ -780,10 +782,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
||||||
data->SetValue(i, vec[i]);
|
data->SetValue(i, vec[i]);
|
||||||
|
|
||||||
grid->GetPointData()->AddArray(data);
|
grid->GetPointData()->AddArray(data);
|
||||||
}
|
}}
|
||||||
|
|
||||||
if(!res->StressValues.getValues().empty()) {
|
if(!res->PrincipalMax.getValues().empty()) {
|
||||||
const std::vector<double>& vec = res->PrincipalMax.getValues();
|
const std::vector<double>& vec = res->PrincipalMax.getValues();
|
||||||
|
if (vec.size()>1) {
|
||||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||||
data->SetNumberOfValues(vec.size());
|
data->SetNumberOfValues(vec.size());
|
||||||
data->SetName("Maximum Principal stress");
|
data->SetName("Maximum Principal stress");
|
||||||
|
@ -792,10 +795,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
||||||
data->SetValue(i, vec[i]);
|
data->SetValue(i, vec[i]);
|
||||||
|
|
||||||
grid->GetPointData()->AddArray(data);
|
grid->GetPointData()->AddArray(data);
|
||||||
}
|
}}
|
||||||
|
|
||||||
if(!res->StressValues.getValues().empty()) {
|
if(!res->PrincipalMax.getValues().empty()) {
|
||||||
const std::vector<double>& vec = res->PrincipalMin.getValues();
|
const std::vector<double>& vec = res->PrincipalMin.getValues();
|
||||||
|
if (vec.size()>1) {
|
||||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||||
data->SetNumberOfValues(vec.size());
|
data->SetNumberOfValues(vec.size());
|
||||||
data->SetName("Minimum Principal stress");
|
data->SetName("Minimum Principal stress");
|
||||||
|
@ -804,10 +808,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
||||||
data->SetValue(i, vec[i]);
|
data->SetValue(i, vec[i]);
|
||||||
|
|
||||||
grid->GetPointData()->AddArray(data);
|
grid->GetPointData()->AddArray(data);
|
||||||
}
|
}}
|
||||||
|
|
||||||
if(!res->StressValues.getValues().empty()) {
|
if (!res->Temperature.getValues().empty()) {
|
||||||
const std::vector<double>& vec = res->Temperature.getValues();
|
const std::vector<double>& vec = res->Temperature.getValues();
|
||||||
|
if (vec.size()>1) {
|
||||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||||
data->SetNumberOfValues(vec.size());
|
data->SetNumberOfValues(vec.size());
|
||||||
data->SetName("Temperature");
|
data->SetName("Temperature");
|
||||||
|
@ -816,10 +821,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
||||||
data->SetValue(i, vec[i]);
|
data->SetValue(i, vec[i]);
|
||||||
|
|
||||||
grid->GetPointData()->AddArray(data);
|
grid->GetPointData()->AddArray(data);
|
||||||
}
|
}}
|
||||||
|
|
||||||
if(!res->StressValues.getValues().empty()) {
|
if (!res->UserDefined.getValues().empty()) {
|
||||||
const std::vector<double>& vec = res->UserDefined.getValues();
|
const std::vector<double>& vec = res->UserDefined.getValues();
|
||||||
|
if (vec.size()>1) {
|
||||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||||
data->SetNumberOfValues(vec.size());
|
data->SetNumberOfValues(vec.size());
|
||||||
data->SetName("User Defined Results");
|
data->SetName("User Defined Results");
|
||||||
|
@ -828,11 +834,12 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
||||||
data->SetValue(i, vec[i]);
|
data->SetValue(i, vec[i]);
|
||||||
|
|
||||||
grid->GetPointData()->AddArray(data);
|
grid->GetPointData()->AddArray(data);
|
||||||
}
|
}}
|
||||||
|
|
||||||
|
|
||||||
if(!res->StressValues.getValues().empty()) {
|
if(!res->DisplacementVectors.getValues().empty()) {
|
||||||
const std::vector<Base::Vector3d>& vec = res->DisplacementVectors.getValues();
|
const std::vector<Base::Vector3d>& vec = res->DisplacementVectors.getValues();
|
||||||
|
if (vec.size()>1) {
|
||||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||||
data->SetNumberOfComponents(3);
|
data->SetNumberOfComponents(3);
|
||||||
data->SetName("Displacement");
|
data->SetName("Displacement");
|
||||||
|
@ -843,7 +850,38 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
||||||
}
|
}
|
||||||
|
|
||||||
grid->GetPointData()->AddArray(data);
|
grid->GetPointData()->AddArray(data);
|
||||||
|
}}
|
||||||
|
|
||||||
|
if(!res->StressVectors.getValues().empty()) {
|
||||||
|
const std::vector<Base::Vector3d>& vec = res->StressVectors.getValues();
|
||||||
|
if (vec.size()>1) {
|
||||||
|
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||||
|
data->SetNumberOfComponents(3);
|
||||||
|
data->SetName("Stress Vectors");
|
||||||
|
|
||||||
|
for(std::vector<Base::Vector3d>::const_iterator it=vec.begin(); it!=vec.end(); ++it) {
|
||||||
|
double tuple[] = {it->x, it->y , it->z};
|
||||||
|
data->InsertNextTuple(tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
grid->GetPointData()->AddArray(data);
|
||||||
|
}}
|
||||||
|
|
||||||
|
if(!res->StrainVectors.getValues().empty()) {
|
||||||
|
const std::vector<Base::Vector3d>& vec = res->StrainVectors.getValues();
|
||||||
|
if (vec.size()>1) {
|
||||||
|
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||||
|
data->SetNumberOfComponents(3);
|
||||||
|
data->SetName("Strain Vectors");
|
||||||
|
|
||||||
|
for(std::vector<Base::Vector3d>::const_iterator it=vec.begin(); it!=vec.end(); ++it) {
|
||||||
|
double tuple[] = {it->x, it->y, it->z};
|
||||||
|
data->InsertNextTuple(tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
grid->GetPointData()->AddArray(data);
|
||||||
|
}}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -55,6 +55,13 @@ INSTALL(
|
||||||
FemMesh2Mesh.py
|
FemMesh2Mesh.py
|
||||||
_CommandFEMMesh2Mesh.py
|
_CommandFEMMesh2Mesh.py
|
||||||
|
|
||||||
|
FemMeshGroup.py
|
||||||
|
_FemMeshGroup.py
|
||||||
|
_ViewProviderFemMeshGroup.py
|
||||||
|
_CommandMeshGroup.py
|
||||||
|
_TaskPanelFemMeshGroup.py
|
||||||
|
TaskPanelFemMeshGroup.ui
|
||||||
|
|
||||||
FemMeshRegion.py
|
FemMeshRegion.py
|
||||||
_FemMeshRegion.py
|
_FemMeshRegion.py
|
||||||
_ViewProviderFemMeshRegion.py
|
_ViewProviderFemMeshRegion.py
|
||||||
|
|
|
@ -215,17 +215,39 @@ class FemGmshTools():
|
||||||
print(' ' + self.gmsh_bin)
|
print(' ' + self.gmsh_bin)
|
||||||
|
|
||||||
def get_group_data(self):
|
def get_group_data(self):
|
||||||
|
self.group_elements = {}
|
||||||
|
# TODO solid, face, edge seam not work together, some print or make it work together
|
||||||
|
# TODO handle groups for Edges and Vertexes
|
||||||
|
|
||||||
|
# mesh groups and groups of analysis member
|
||||||
|
if not self.mesh_obj.MeshGroupList:
|
||||||
|
print (' No mesh group objects.')
|
||||||
|
else:
|
||||||
|
print (' Mesh group objects, we need to get the elements.')
|
||||||
|
for mg in self.mesh_obj.MeshGroupList:
|
||||||
|
new_group_elements = FemMeshTools.get_mesh_group_elements(mg, self.part_obj)
|
||||||
|
for ge in new_group_elements:
|
||||||
|
if ge not in self.group_elements:
|
||||||
|
self.group_elements[ge] = new_group_elements[ge]
|
||||||
|
else:
|
||||||
|
FreeCAD.Console.PrintError(" A group with this name exists already.\n")
|
||||||
if self.analysis:
|
if self.analysis:
|
||||||
print(' Group meshing.')
|
print(' Group meshing.')
|
||||||
self.group_elements = FemMeshTools.get_analysis_group_elements(self.analysis, self.part_obj)
|
new_group_elements = FemMeshTools.get_analysis_group_elements(self.analysis, self.part_obj)
|
||||||
print(' {}'.format(self.group_elements))
|
for ge in new_group_elements:
|
||||||
|
if ge not in self.group_elements:
|
||||||
|
self.group_elements[ge] = new_group_elements[ge]
|
||||||
else:
|
else:
|
||||||
print(' NO group meshing.')
|
FreeCAD.Console.PrintError(" A group with this name exists already.\n")
|
||||||
|
else:
|
||||||
|
print(' No anlysis members for group meshing.')
|
||||||
|
print(' {}'.format(self.group_elements))
|
||||||
|
|
||||||
|
# mesh regions
|
||||||
self.ele_length_map = {} # { 'ElementString' : element length }
|
self.ele_length_map = {} # { 'ElementString' : element length }
|
||||||
self.ele_node_map = {} # { 'ElementString' : [element nodes] }
|
self.ele_node_map = {} # { 'ElementString' : [element nodes] }
|
||||||
if not self.mesh_obj.MeshRegionList:
|
if not self.mesh_obj.MeshRegionList:
|
||||||
print (' No Mesh regions.')
|
print (' No mesh regions.')
|
||||||
else:
|
else:
|
||||||
print (' Mesh regions, we need to get the elements.')
|
print (' Mesh regions, we need to get the elements.')
|
||||||
if self.part_obj.Shape.ShapeType == 'Compound':
|
if self.part_obj.Shape.ShapeType == 'Compound':
|
||||||
|
@ -279,7 +301,7 @@ class FemGmshTools():
|
||||||
geo = open(self.temp_file_geo, "w")
|
geo = open(self.temp_file_geo, "w")
|
||||||
geo.write('Merge "' + self.temp_file_geometry + '";\n')
|
geo.write('Merge "' + self.temp_file_geometry + '";\n')
|
||||||
geo.write("\n")
|
geo.write("\n")
|
||||||
if self.analysis and self.group_elements:
|
if self.group_elements:
|
||||||
# print(' We gone have found elements to make mesh groups for.')
|
# print(' We gone have found elements to make mesh groups for.')
|
||||||
geo.write("// group data\n")
|
geo.write("// group data\n")
|
||||||
# we use the element name of FreeCAD which starts with 1 (example: 'Face1'), same as GMSH
|
# we use the element name of FreeCAD which starts with 1 (example: 'Face1'), same as GMSH
|
||||||
|
|
49
src/Mod/Fem/FemMeshGroup.py
Normal file
49
src/Mod/Fem/FemMeshGroup.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# ***************************************************************************
|
||||||
|
# * *
|
||||||
|
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
|
||||||
|
# * *
|
||||||
|
# * This program is free software; you can redistribute it and/or modify *
|
||||||
|
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||||
|
# * as published by the Free Software Foundation; either version 2 of *
|
||||||
|
# * the License, or (at your option) any later version. *
|
||||||
|
# * for detail see the LICENCE text file. *
|
||||||
|
# * *
|
||||||
|
# * This program is distributed in the hope that it will be useful, *
|
||||||
|
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
# * GNU Library General Public License for more details. *
|
||||||
|
# * *
|
||||||
|
# * You should have received a copy of the GNU Library General Public *
|
||||||
|
# * License along with this program; if not, write to the Free Software *
|
||||||
|
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
# * USA *
|
||||||
|
# * *
|
||||||
|
# ***************************************************************************
|
||||||
|
|
||||||
|
__title__ = "FemMeshGroup"
|
||||||
|
__author__ = "Bernd Hahnebach"
|
||||||
|
__url__ = "http://www.freecadweb.org"
|
||||||
|
|
||||||
|
## \addtogroup FEM
|
||||||
|
# @{
|
||||||
|
|
||||||
|
import FreeCAD
|
||||||
|
import _FemMeshGroup
|
||||||
|
|
||||||
|
|
||||||
|
def makeFemMeshGroup(base_mesh, use_label=False, name="FEMMeshGroup"):
|
||||||
|
'''makeFemMeshGroup([length], [name]): creates a FEM mesh region object to define properties for a regon of a FEM mesh'''
|
||||||
|
obj = FreeCAD.ActiveDocument.addObject("Fem::FeaturePython", name)
|
||||||
|
_FemMeshGroup._FemMeshGroup(obj)
|
||||||
|
obj.UseLabel = use_label
|
||||||
|
# obj.BaseMesh = base_mesh
|
||||||
|
# App::PropertyLinkList does not support append, we will use a temporary list to append the mesh group obj. to the list
|
||||||
|
tmplist = base_mesh.MeshGroupList
|
||||||
|
tmplist.append(obj)
|
||||||
|
base_mesh.MeshGroupList = tmplist
|
||||||
|
if FreeCAD.GuiUp:
|
||||||
|
import _ViewProviderFemMeshGroup
|
||||||
|
_ViewProviderFemMeshGroup._ViewProviderFemMeshGroup(obj.ViewObject)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
# @}
|
|
@ -995,21 +995,60 @@ def get_ref_shape_node_sum_geom_table(node_geom_table):
|
||||||
return node_sum_geom_table
|
return node_sum_geom_table
|
||||||
|
|
||||||
|
|
||||||
|
def get_mesh_group_elements(mesh_group_obj, aPart):
|
||||||
|
'''the Reference shapes of the mesh_group_object are searched in the Shape of aPart. If found in shape they are added to a dict
|
||||||
|
{MeshGroupIdentifier : ['ShapeType of the Elements'], [ElementID, ElementID, ...], ...}
|
||||||
|
'''
|
||||||
|
group_elements = {} # { name : [element, element, ... , element]}
|
||||||
|
if mesh_group_obj.References:
|
||||||
|
grp_ele = get_reference_group_elements(mesh_group_obj, aPart)
|
||||||
|
group_elements[grp_ele[0]] = grp_ele[1]
|
||||||
|
else:
|
||||||
|
FreeCAD.Console.PrintError(' Empty reference in mesh group object: ' + mesh_group_obj.Name + ' ' + mesh_group_obj.Label)
|
||||||
|
return group_elements
|
||||||
|
|
||||||
|
|
||||||
def get_analysis_group_elements(aAnalysis, aPart):
|
def get_analysis_group_elements(aAnalysis, aPart):
|
||||||
''' all Reference shapes of all Analysis member are searched in the Shape of aPart. If found in shape they are added to a dict
|
''' all Reference shapes of all Analysis member are searched in the Shape of aPart. If found in shape they are added to a dict
|
||||||
{ConstraintName : ['ShapeType of the Elements'], [ElementID, ElementID, ...], ...}
|
{ConstraintName : ['ShapeType of the Elements'], [ElementID, ElementID, ...], ...}
|
||||||
'''
|
'''
|
||||||
aShape = aPart.Shape
|
|
||||||
group_elements = {} # { name : [element, element, ... , element]}
|
group_elements = {} # { name : [element, element, ... , element]}
|
||||||
empty_references = []
|
empty_references = []
|
||||||
for m in aAnalysis.Member:
|
for m in aAnalysis.Member:
|
||||||
if hasattr(m, "References"):
|
if hasattr(m, "References"):
|
||||||
# print(m.Name)
|
if m.References:
|
||||||
key = m.Name
|
grp_ele = get_reference_group_elements(m, aPart)
|
||||||
|
group_elements[grp_ele[0]] = grp_ele[1]
|
||||||
|
else:
|
||||||
|
print(' Empty reference: ' + m.Name)
|
||||||
|
empty_references.append(m)
|
||||||
|
if empty_references:
|
||||||
|
if len(empty_references) == 1:
|
||||||
|
group_elements = get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aPart.Shape)
|
||||||
|
else:
|
||||||
|
FreeCAD.Console.PrintError('Problem: more than one object with empty references.\n')
|
||||||
|
print('We gone try to get the empty material references anyway.\n')
|
||||||
|
# ShellThickness and BeamSection could have empty references, but on solid meshes only materials should have empty references
|
||||||
|
for er in empty_references:
|
||||||
|
print(er.Name)
|
||||||
|
group_elements = get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aPart.Shape)
|
||||||
|
# check if all groups have elements:
|
||||||
|
for g in group_elements:
|
||||||
|
# print(group_elements[g])
|
||||||
|
if len(group_elements[g]) == 0:
|
||||||
|
FreeCAD.Console.PrintError('Error: shapes for: ' + g + 'not found!\n')
|
||||||
|
return group_elements
|
||||||
|
|
||||||
|
|
||||||
|
def get_reference_group_elements(obj, aPart):
|
||||||
|
aShape = aPart.Shape
|
||||||
|
if hasattr(obj, "UseLabel") and obj.UseLabel:
|
||||||
|
key = obj.Label # TODO check the character of the Label, only allow underline and standard english character
|
||||||
|
else:
|
||||||
|
key = obj.Name
|
||||||
elements = []
|
elements = []
|
||||||
stype = None
|
stype = None
|
||||||
if m.References:
|
for r in obj.References:
|
||||||
for r in m.References:
|
|
||||||
parent = r[0]
|
parent = r[0]
|
||||||
childs = r[1]
|
childs = r[1]
|
||||||
# print(parent)
|
# print(parent)
|
||||||
|
@ -1026,29 +1065,10 @@ def get_analysis_group_elements(aAnalysis, aPart):
|
||||||
elements.append(found_element)
|
elements.append(found_element)
|
||||||
else:
|
else:
|
||||||
FreeCAD.Console.PrintError('Problem: No element found for: ' + str(ref_shape) + '\n')
|
FreeCAD.Console.PrintError('Problem: No element found for: ' + str(ref_shape) + '\n')
|
||||||
print(' ' + m.Name)
|
print(' ' + obj.Name)
|
||||||
print(' ' + str(m.References))
|
print(' ' + str(obj.References))
|
||||||
print(' ' + r[0].Name)
|
print(' ' + r[0].Name)
|
||||||
group_elements[key] = sorted(elements)
|
return (key, sorted(elements))
|
||||||
else:
|
|
||||||
print(' Empty reference: ' + m.Name)
|
|
||||||
empty_references.append(m)
|
|
||||||
if empty_references:
|
|
||||||
if len(empty_references) == 1:
|
|
||||||
group_elements = get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape)
|
|
||||||
else:
|
|
||||||
FreeCAD.Console.PrintError('Problem: more than one object with empty references.\n')
|
|
||||||
print('We gone try to get the empty material references anyway.\n')
|
|
||||||
# ShellThickness and BeamSection could have empty references, but on solid meshes only materials should have empty references
|
|
||||||
for er in empty_references:
|
|
||||||
print(er.Name)
|
|
||||||
group_elements = get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape)
|
|
||||||
# check if all groups have elements:
|
|
||||||
for g in group_elements:
|
|
||||||
# print(group_elements[g])
|
|
||||||
if len(group_elements[g]) == 0:
|
|
||||||
FreeCAD.Console.PrintError('Error: shapes for: ' + g + 'not found!\n')
|
|
||||||
return group_elements
|
|
||||||
|
|
||||||
|
|
||||||
def get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape):
|
def get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape):
|
||||||
|
|
|
@ -378,9 +378,7 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
|
||||||
if self.analysis_type == "static":
|
if self.analysis_type == "static":
|
||||||
if not (self.fixed_constraints or self.displacement_constraints):
|
if not (self.fixed_constraints or self.displacement_constraints):
|
||||||
message += "Static analysis: Neither constraint fixed nor constraint displacement defined.\n"
|
message += "Static analysis: Neither constraint fixed nor constraint displacement defined.\n"
|
||||||
if self.analysis_type == "static":
|
# no check in the regard of loads (constraint force, pressure, self weight) is done because an analysis without loads at all is an valid analysis too
|
||||||
if not (self.force_constraints or self.pressure_constraints or self.selfweight_constraints):
|
|
||||||
message += "Static analysis: Neither constraint force nor constraint pressure or a constraint selfweight defined.\n"
|
|
||||||
if self.analysis_type == "thermomech":
|
if self.analysis_type == "thermomech":
|
||||||
if not self.initialtemperature_constraints:
|
if not self.initialtemperature_constraints:
|
||||||
message += "Thermomechanical analysis: No initial temperature defined.\n"
|
message += "Thermomechanical analysis: No initial temperature defined.\n"
|
||||||
|
|
|
@ -71,6 +71,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||||
<< "Fem_MeshNetgenFromShape"
|
<< "Fem_MeshNetgenFromShape"
|
||||||
<< "Fem_MeshGmshFromShape"
|
<< "Fem_MeshGmshFromShape"
|
||||||
<< "Fem_MeshRegion"
|
<< "Fem_MeshRegion"
|
||||||
|
<< "Fem_MeshGroup"
|
||||||
//<< "Fem_CreateNodesSet"
|
//<< "Fem_CreateNodesSet"
|
||||||
<< "Separator"
|
<< "Separator"
|
||||||
<< "Fem_Material"
|
<< "Fem_Material"
|
||||||
|
@ -143,6 +144,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||||
<< "Fem_MeshNetgenFromShape"
|
<< "Fem_MeshNetgenFromShape"
|
||||||
<< "Fem_MeshGmshFromShape"
|
<< "Fem_MeshGmshFromShape"
|
||||||
<< "Fem_MeshRegion"
|
<< "Fem_MeshRegion"
|
||||||
|
<< "Fem_MeshGroup"
|
||||||
<< "Fem_CreateNodesSet"
|
<< "Fem_CreateNodesSet"
|
||||||
<< "Separator"
|
<< "Separator"
|
||||||
<< "Fem_Material"
|
<< "Fem_Material"
|
||||||
|
|
|
@ -54,6 +54,7 @@ class FemWorkbench (Workbench):
|
||||||
import _CommandFEMMesh2Mesh
|
import _CommandFEMMesh2Mesh
|
||||||
import _CommandMeshGmshFromShape
|
import _CommandMeshGmshFromShape
|
||||||
import _CommandMeshNetgenFromShape
|
import _CommandMeshNetgenFromShape
|
||||||
|
import _CommandMeshGroup
|
||||||
import _CommandMeshRegion
|
import _CommandMeshRegion
|
||||||
import _CommandAnalysis
|
import _CommandAnalysis
|
||||||
import _CommandShellThickness
|
import _CommandShellThickness
|
||||||
|
|
120
src/Mod/Fem/TaskPanelFemMeshGroup.ui
Normal file
120
src/Mod/Fem/TaskPanelFemMeshGroup.ui
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>350</width>
|
||||||
|
<height>500</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Mesh group</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>1677215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Identifier used for mesh export</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout_1">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QRadioButton" name="rb_name">
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QRadioButton" name="rb_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Label</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_1">
|
||||||
|
<property name="title">
|
||||||
|
<string>References</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_Reference">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add reference</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="list_References"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QRadioButton" name="rb_solid">
|
||||||
|
<property name="text">
|
||||||
|
<string>Solid</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QRadioButton" name="rb_standard">
|
||||||
|
<property name="text">
|
||||||
|
<string>Face, Edge, Vertex</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="l_label_text_5">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p>Selection</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -270,8 +270,38 @@
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="user_def_text">
|
<widget class="QLabel" name="user_def_text">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>17</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Available: Disp(x,y,z) Principal stresses (P1,P2,P3)</string>
|
<string>Available: Disp(x,y,z) Principal stresses(P1,P2,P3) Stress(sx,sy,sz) Strain (ex,ey,ez)</string>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::NoTextInteraction</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
57
src/Mod/Fem/_CommandMeshGroup.py
Normal file
57
src/Mod/Fem/_CommandMeshGroup.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# ***************************************************************************
|
||||||
|
# * *
|
||||||
|
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
|
||||||
|
# * *
|
||||||
|
# * This program is free software; you can redistribute it and/or modify *
|
||||||
|
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||||
|
# * as published by the Free Software Foundation; either version 2 of *
|
||||||
|
# * the License, or (at your option) any later version. *
|
||||||
|
# * for detail see the LICENCE text file. *
|
||||||
|
# * *
|
||||||
|
# * This program is distributed in the hope that it will be useful, *
|
||||||
|
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
# * GNU Library General Public License for more details. *
|
||||||
|
# * *
|
||||||
|
# * You should have received a copy of the GNU Library General Public *
|
||||||
|
# * License along with this program; if not, write to the Free Software *
|
||||||
|
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
# * USA *
|
||||||
|
# * *
|
||||||
|
# ***************************************************************************
|
||||||
|
|
||||||
|
__title__ = "_CommandMeshGroup"
|
||||||
|
__author__ = "Bernd Hahnebach"
|
||||||
|
__url__ = "http://www.freecadweb.org"
|
||||||
|
|
||||||
|
## @package CommandMeshGroup
|
||||||
|
# \ingroup FEM
|
||||||
|
|
||||||
|
import FreeCAD
|
||||||
|
from FemCommands import FemCommands
|
||||||
|
import FreeCADGui
|
||||||
|
from PySide import QtCore
|
||||||
|
|
||||||
|
|
||||||
|
class _CommandMeshGroup(FemCommands):
|
||||||
|
"The Fem_MeshGroup command definition"
|
||||||
|
def __init__(self):
|
||||||
|
super(_CommandMeshGroup, self).__init__()
|
||||||
|
self.resources = {'Pixmap': 'fem-femmesh-from-shape',
|
||||||
|
'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGroup", "FEM mesh group"),
|
||||||
|
'Accel': "M, G",
|
||||||
|
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGroup", "Creates a FEM mesh group")}
|
||||||
|
self.is_active = 'with_gmsh_femmesh'
|
||||||
|
|
||||||
|
def Activated(self):
|
||||||
|
FreeCAD.ActiveDocument.openTransaction("Create FemMeshGroup")
|
||||||
|
FreeCADGui.addModule("FemMeshGroup")
|
||||||
|
sel = FreeCADGui.Selection.getSelection()
|
||||||
|
if (len(sel) == 1):
|
||||||
|
sobj = sel[0]
|
||||||
|
if len(sel) == 1 and hasattr(sobj, "Proxy") and sobj.Proxy.Type == "FemMeshGmsh":
|
||||||
|
FreeCADGui.doCommand("FemMeshGroup.makeFemMeshGroup(App.ActiveDocument." + sobj.Name + ")")
|
||||||
|
|
||||||
|
FreeCADGui.Selection.clearSelection()
|
||||||
|
|
||||||
|
FreeCADGui.addCommand('Fem_MeshGroup', _CommandMeshGroup())
|
|
@ -46,6 +46,9 @@ class _FemMeshGmsh():
|
||||||
obj.addProperty("App::PropertyLinkList", "MeshRegionList", "Base", "Mesh regions of the mesh")
|
obj.addProperty("App::PropertyLinkList", "MeshRegionList", "Base", "Mesh regions of the mesh")
|
||||||
obj.MeshRegionList = []
|
obj.MeshRegionList = []
|
||||||
|
|
||||||
|
obj.addProperty("App::PropertyLinkList", "MeshGroupList", "Base", "Mesh groups of the mesh")
|
||||||
|
obj.MeshRegionList = []
|
||||||
|
|
||||||
obj.addProperty("App::PropertyLink", "Part", "FEM Mesh", "Part object to mesh")
|
obj.addProperty("App::PropertyLink", "Part", "FEM Mesh", "Part object to mesh")
|
||||||
obj.Part = None
|
obj.Part = None
|
||||||
|
|
||||||
|
|
40
src/Mod/Fem/_FemMeshGroup.py
Normal file
40
src/Mod/Fem/_FemMeshGroup.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# ***************************************************************************
|
||||||
|
# * *
|
||||||
|
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
|
||||||
|
# * *
|
||||||
|
# * This program is free software; you can redistribute it and/or modify *
|
||||||
|
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||||
|
# * as published by the Free Software Foundation; either version 2 of *
|
||||||
|
# * the License, or (at your option) any later version. *
|
||||||
|
# * for detail see the LICENCE text file. *
|
||||||
|
# * *
|
||||||
|
# * This program is distributed in the hope that it will be useful, *
|
||||||
|
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
# * GNU Library General Public License for more details. *
|
||||||
|
# * *
|
||||||
|
# * You should have received a copy of the GNU Library General Public *
|
||||||
|
# * License along with this program; if not, write to the Free Software *
|
||||||
|
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
# * USA *
|
||||||
|
# * *
|
||||||
|
# ***************************************************************************
|
||||||
|
|
||||||
|
__title__ = "_FemMeshGroup"
|
||||||
|
__author__ = "Bernd Hahnebach"
|
||||||
|
__url__ = "http://www.freecadweb.org"
|
||||||
|
|
||||||
|
## @package FemMeshGroup
|
||||||
|
# \ingroup FEM
|
||||||
|
|
||||||
|
|
||||||
|
class _FemMeshGroup:
|
||||||
|
"The FemMeshGroup object"
|
||||||
|
def __init__(self, obj):
|
||||||
|
obj.addProperty("App::PropertyBool", "UseLabel", "MeshGroupProperties", "The identifier used for export (True: Label, False: Name)")
|
||||||
|
obj.addProperty("App::PropertyLinkSubList", "References", "MeshGroupShapes", "List of FEM mesh group shapes")
|
||||||
|
obj.Proxy = self
|
||||||
|
self.Type = "FemMeshGroup"
|
||||||
|
|
||||||
|
def execute(self, obj):
|
||||||
|
return
|
190
src/Mod/Fem/_TaskPanelFemMeshGroup.py
Normal file
190
src/Mod/Fem/_TaskPanelFemMeshGroup.py
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
# ***************************************************************************
|
||||||
|
# * *
|
||||||
|
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
|
||||||
|
# * *
|
||||||
|
# * This program is free software; you can redistribute it and/or modify *
|
||||||
|
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||||
|
# * as published by the Free Software Foundation; either version 2 of *
|
||||||
|
# * the License, or (at your option) any later version. *
|
||||||
|
# * for detail see the LICENCE text file. *
|
||||||
|
# * *
|
||||||
|
# * This program is distributed in the hope that it will be useful, *
|
||||||
|
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
# * GNU Library General Public License for more details. *
|
||||||
|
# * *
|
||||||
|
# * You should have received a copy of the GNU Library General Public *
|
||||||
|
# * License along with this program; if not, write to the Free Software *
|
||||||
|
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
# * USA *
|
||||||
|
# * *
|
||||||
|
# ***************************************************************************
|
||||||
|
|
||||||
|
__title__ = "_TaskPanelFemMeshGroup"
|
||||||
|
__author__ = "Bernd Hahnebach"
|
||||||
|
__url__ = "http://www.freecadweb.org"
|
||||||
|
|
||||||
|
## @package TaskPanelFemMeshGroup
|
||||||
|
# \ingroup FEM
|
||||||
|
|
||||||
|
import FreeCAD
|
||||||
|
import FreeCADGui
|
||||||
|
from PySide import QtGui
|
||||||
|
from PySide import QtCore
|
||||||
|
|
||||||
|
|
||||||
|
class _TaskPanelFemMeshGroup:
|
||||||
|
'''The TaskPanel for editing References property of FemMeshGroup objects'''
|
||||||
|
def __init__(self, obj):
|
||||||
|
FreeCADGui.Selection.clearSelection()
|
||||||
|
self.sel_server = None
|
||||||
|
self.obj = obj
|
||||||
|
self.selection_mode_solid = False
|
||||||
|
self.selection_mode_std_print_message = "Select Faces, Edges and Vertices by single click on them to add them to the list."
|
||||||
|
self.selection_mode_solid_print_message = "Select Solids by single click on a Face or Edge which belongs to the Solid, to add the Solid to the list."
|
||||||
|
|
||||||
|
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/TaskPanelFemMeshGroup.ui")
|
||||||
|
QtCore.QObject.connect(self.form.rb_name, QtCore.SIGNAL("toggled(bool)"), self.choose_exportidentifier_name)
|
||||||
|
QtCore.QObject.connect(self.form.rb_label, QtCore.SIGNAL("toggled(bool)"), self.choose_exportidentifier_label)
|
||||||
|
QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard)
|
||||||
|
QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid)
|
||||||
|
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
|
||||||
|
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||||
|
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
|
||||||
|
|
||||||
|
self.get_meshgroup_props()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
self.set_meshgroup_props()
|
||||||
|
if self.sel_server:
|
||||||
|
FreeCADGui.Selection.removeObserver(self.sel_server)
|
||||||
|
FreeCADGui.ActiveDocument.resetEdit()
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def reject(self):
|
||||||
|
if self.sel_server:
|
||||||
|
FreeCADGui.Selection.removeObserver(self.sel_server)
|
||||||
|
FreeCADGui.ActiveDocument.resetEdit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_meshgroup_props(self):
|
||||||
|
self.use_label = self.obj.UseLabel
|
||||||
|
self.references = []
|
||||||
|
if self.obj.References:
|
||||||
|
self.tuplereferences = self.obj.References
|
||||||
|
self.get_references()
|
||||||
|
|
||||||
|
def set_meshgroup_props(self):
|
||||||
|
self.obj.References = self.references
|
||||||
|
self.obj.UseLabel = self.use_label
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
'fills the widgets'
|
||||||
|
self.form.rb_name.setChecked(not self.use_label)
|
||||||
|
self.form.rb_label.setChecked(self.use_label)
|
||||||
|
self.rebuild_list_References()
|
||||||
|
|
||||||
|
def choose_exportidentifier_name(self, state):
|
||||||
|
self.use_label = not state
|
||||||
|
|
||||||
|
def choose_exportidentifier_label(self, state):
|
||||||
|
self.use_label = state
|
||||||
|
|
||||||
|
def choose_selection_mode_standard(self, state):
|
||||||
|
self.selection_mode_solid = not state
|
||||||
|
if self.sel_server and not self.selection_mode_solid:
|
||||||
|
print(self.selection_mode_std_print_message)
|
||||||
|
|
||||||
|
def choose_selection_mode_solid(self, state):
|
||||||
|
self.selection_mode_solid = state
|
||||||
|
if self.sel_server and self.selection_mode_solid:
|
||||||
|
print(self.selection_mode_solid_print_message)
|
||||||
|
|
||||||
|
def get_references(self):
|
||||||
|
for ref in self.tuplereferences:
|
||||||
|
for elem in ref[1]:
|
||||||
|
self.references.append((ref[0], elem))
|
||||||
|
|
||||||
|
def references_list_right_clicked(self, QPos):
|
||||||
|
self.form.contextMenu = QtGui.QMenu()
|
||||||
|
menu_item = self.form.contextMenu.addAction("Remove Reference")
|
||||||
|
if not self.references:
|
||||||
|
menu_item.setDisabled(True)
|
||||||
|
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
|
||||||
|
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
|
||||||
|
self.form.contextMenu.move(parentPosition + QPos)
|
||||||
|
self.form.contextMenu.show()
|
||||||
|
|
||||||
|
def remove_reference(self):
|
||||||
|
if not self.references:
|
||||||
|
return
|
||||||
|
currentItemName = str(self.form.list_References.currentItem().text())
|
||||||
|
for ref in self.references:
|
||||||
|
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
|
||||||
|
if refname_to_compare_listentry == currentItemName:
|
||||||
|
self.references.remove(ref)
|
||||||
|
self.rebuild_list_References()
|
||||||
|
|
||||||
|
def add_references(self):
|
||||||
|
'''Called if Button add_reference is triggered'''
|
||||||
|
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
|
||||||
|
# here the addReference button EditTaskPanel has to be triggered to start selection mode
|
||||||
|
FreeCADGui.Selection.clearSelection()
|
||||||
|
# start SelectionObserver and parse the function to add the References to the widget
|
||||||
|
if self.selection_mode_solid: # print message on button click
|
||||||
|
print_message = self.selection_mode_solid_print_message
|
||||||
|
else:
|
||||||
|
print_message = self.selection_mode_std_print_message
|
||||||
|
import FemSelectionObserver
|
||||||
|
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
|
||||||
|
|
||||||
|
def selectionParser(self, selection):
|
||||||
|
print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
|
||||||
|
if hasattr(selection[0], "Shape") and selection[1]:
|
||||||
|
elt = selection[0].Shape.getElement(selection[1])
|
||||||
|
if self.selection_mode_solid:
|
||||||
|
# in solid selection mode use edges and faces for selection of a solid
|
||||||
|
solid_to_add = None
|
||||||
|
if elt.ShapeType == 'Edge':
|
||||||
|
found_edge = False
|
||||||
|
for i, s in enumerate(selection[0].Shape.Solids):
|
||||||
|
for e in s.Edges:
|
||||||
|
if elt.isSame(e):
|
||||||
|
if not found_edge:
|
||||||
|
solid_to_add = str(i + 1)
|
||||||
|
else:
|
||||||
|
FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
|
||||||
|
solid_to_add = None
|
||||||
|
found_edge = True
|
||||||
|
elif elt.ShapeType == 'Face':
|
||||||
|
found_face = False
|
||||||
|
for i, s in enumerate(selection[0].Shape.Solids):
|
||||||
|
for e in s.Faces:
|
||||||
|
if elt.isSame(e):
|
||||||
|
if not found_face:
|
||||||
|
solid_to_add = str(i + 1)
|
||||||
|
else:
|
||||||
|
FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
|
||||||
|
solid_to_add = None
|
||||||
|
found_edge = True
|
||||||
|
if solid_to_add:
|
||||||
|
selection = (selection[0], 'Solid' + solid_to_add)
|
||||||
|
print('selection element changed to Solid: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
if selection not in self.references:
|
||||||
|
self.references.append(selection)
|
||||||
|
self.rebuild_list_References()
|
||||||
|
else:
|
||||||
|
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
|
||||||
|
|
||||||
|
def rebuild_list_References(self):
|
||||||
|
self.form.list_References.clear()
|
||||||
|
items = []
|
||||||
|
for ref in self.references:
|
||||||
|
item_name = ref[0].Name + ':' + ref[1]
|
||||||
|
items.append(item_name)
|
||||||
|
for listItemName in sorted(items):
|
||||||
|
self.form.list_References.addItem(listItemName)
|
|
@ -21,7 +21,7 @@
|
||||||
# ***************************************************************************
|
# ***************************************************************************
|
||||||
|
|
||||||
__title__ = "Result Control Task Panel"
|
__title__ = "Result Control Task Panel"
|
||||||
__author__ = "Juergen Riegel"
|
__author__ = "Juergen Riegel, Michael Hindley"
|
||||||
__url__ = "http://www.freecadweb.org"
|
__url__ = "http://www.freecadweb.org"
|
||||||
|
|
||||||
## @package TaskPanelShowResult
|
## @package TaskPanelShowResult
|
||||||
|
@ -231,7 +231,15 @@ class _TaskPanelShowResult:
|
||||||
x = np.array(dispvectors[:, 0])
|
x = np.array(dispvectors[:, 0])
|
||||||
y = np.array(dispvectors[:, 1])
|
y = np.array(dispvectors[:, 1])
|
||||||
z = np.array(dispvectors[:, 2])
|
z = np.array(dispvectors[:, 2])
|
||||||
userdefined_eq = x + y + z + T + Von + P1 + P2 + P3 # Dummy equation to get around flake8, varibles not being used
|
stressvectors = np.array(self.result_object.StressVectors)
|
||||||
|
sx = np.array(stressvectors[:, 0])
|
||||||
|
sy = np.array(stressvectors[:, 1])
|
||||||
|
sz = np.array(stressvectors[:, 2])
|
||||||
|
strainvectors = np.array(self.result_object.StrainVectors)
|
||||||
|
ex = np.array(strainvectors[:, 0])
|
||||||
|
ey = np.array(strainvectors[:, 1])
|
||||||
|
ez = np.array(strainvectors[:, 2])
|
||||||
|
userdefined_eq = x + y + z + T + Von + P1 + P2 + P3 + sx + sy + sz + ex + ey + ez # Dummy equation to get around flake8, varibles not being used
|
||||||
userdefined_eq = self.form.user_def_eq.toPlainText() # Get equation to be used
|
userdefined_eq = self.form.user_def_eq.toPlainText() # Get equation to be used
|
||||||
UserDefinedFormula = eval(userdefined_eq).tolist()
|
UserDefinedFormula = eval(userdefined_eq).tolist()
|
||||||
self.result_object.UserDefined = UserDefinedFormula
|
self.result_object.UserDefined = UserDefinedFormula
|
||||||
|
|
|
@ -112,7 +112,7 @@ class _ViewProviderFemMeshGmsh:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def claimChildren(self):
|
def claimChildren(self):
|
||||||
return self.Object.MeshRegionList
|
return (self.Object.MeshRegionList + self.Object.MeshGroupList)
|
||||||
|
|
||||||
def onDelete(self, feature, subelements):
|
def onDelete(self, feature, subelements):
|
||||||
try:
|
try:
|
||||||
|
|
89
src/Mod/Fem/_ViewProviderFemMeshGroup.py
Normal file
89
src/Mod/Fem/_ViewProviderFemMeshGroup.py
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
# ***************************************************************************
|
||||||
|
# * *
|
||||||
|
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
|
||||||
|
# * *
|
||||||
|
# * This program is free software; you can redistribute it and/or modify *
|
||||||
|
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||||
|
# * as published by the Free Software Foundation; either version 2 of *
|
||||||
|
# * the License, or (at your option) any later version. *
|
||||||
|
# * for detail see the LICENCE text file. *
|
||||||
|
# * *
|
||||||
|
# * This program is distributed in the hope that it will be useful, *
|
||||||
|
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
# * GNU Library General Public License for more details. *
|
||||||
|
# * *
|
||||||
|
# * You should have received a copy of the GNU Library General Public *
|
||||||
|
# * License along with this program; if not, write to the Free Software *
|
||||||
|
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
# * USA *
|
||||||
|
# * *
|
||||||
|
# ***************************************************************************
|
||||||
|
|
||||||
|
__title__ = "_ViewProviderFemMeshGroup"
|
||||||
|
__author__ = "Bernd Hahnebach"
|
||||||
|
__url__ = "http://www.freecadweb.org"
|
||||||
|
|
||||||
|
## @package ViewProviderFemMeshGroup
|
||||||
|
# \ingroup FEM
|
||||||
|
|
||||||
|
import FreeCAD
|
||||||
|
import FreeCADGui
|
||||||
|
from pivy import coin
|
||||||
|
|
||||||
|
|
||||||
|
class _ViewProviderFemMeshGroup:
|
||||||
|
"A View Provider for the FemMeshGroup object"
|
||||||
|
def __init__(self, vobj):
|
||||||
|
vobj.Proxy = self
|
||||||
|
|
||||||
|
def getIcon(self):
|
||||||
|
return ":/icons/fem-femmesh-from-shape.svg"
|
||||||
|
|
||||||
|
def attach(self, vobj):
|
||||||
|
self.ViewObject = vobj
|
||||||
|
self.Object = vobj.Object
|
||||||
|
self.standard = coin.SoGroup()
|
||||||
|
vobj.addDisplayMode(self.standard, "Standard")
|
||||||
|
|
||||||
|
def getDisplayModes(self, obj):
|
||||||
|
return ["Standard"]
|
||||||
|
|
||||||
|
def getDefaultDisplayMode(self):
|
||||||
|
return "Standard"
|
||||||
|
|
||||||
|
def updateData(self, obj, prop):
|
||||||
|
return
|
||||||
|
|
||||||
|
def onChanged(self, vobj, prop):
|
||||||
|
return
|
||||||
|
|
||||||
|
def setEdit(self, vobj, mode=0):
|
||||||
|
# hide all meshes
|
||||||
|
for o in FreeCAD.ActiveDocument.Objects:
|
||||||
|
if o.isDerivedFrom("Fem::FemMeshObject"):
|
||||||
|
o.ViewObject.hide()
|
||||||
|
# show task panel
|
||||||
|
import _TaskPanelFemMeshGroup
|
||||||
|
taskd = _TaskPanelFemMeshGroup._TaskPanelFemMeshGroup(self.Object)
|
||||||
|
taskd.obj = vobj.Object
|
||||||
|
FreeCADGui.Control.showDialog(taskd)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def unsetEdit(self, vobj, mode=0):
|
||||||
|
FreeCADGui.Control.closeDialog()
|
||||||
|
return
|
||||||
|
|
||||||
|
def doubleClicked(self, vobj):
|
||||||
|
doc = FreeCADGui.getDocument(vobj.Object.Document)
|
||||||
|
if not doc.getInEdit():
|
||||||
|
doc.setEdit(vobj.Object.Name)
|
||||||
|
else:
|
||||||
|
FreeCAD.Console.PrintError('Active Task Dialog found! Please close this one first!\n')
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __setstate__(self, state):
|
||||||
|
return None
|
|
@ -54,15 +54,19 @@ def readResult(frd_input):
|
||||||
elements_quad4 = {}
|
elements_quad4 = {}
|
||||||
elements_quad8 = {}
|
elements_quad8 = {}
|
||||||
elements_seg2 = {}
|
elements_seg2 = {}
|
||||||
|
elements_seg3 = {}
|
||||||
results = []
|
results = []
|
||||||
mode_results = {}
|
mode_results = {}
|
||||||
mode_disp = {}
|
mode_disp = {}
|
||||||
mode_stress = {}
|
mode_stress = {}
|
||||||
|
mode_stressv = {}
|
||||||
|
mode_strain = {}
|
||||||
mode_temp = {}
|
mode_temp = {}
|
||||||
|
|
||||||
mode_disp_found = False
|
mode_disp_found = False
|
||||||
nodes_found = False
|
nodes_found = False
|
||||||
mode_stress_found = False
|
mode_stress_found = False
|
||||||
|
mode_strain_found = False
|
||||||
mode_temp_found = False
|
mode_temp_found = False
|
||||||
mode_time_found = False
|
mode_time_found = False
|
||||||
elements_found = False
|
elements_found = False
|
||||||
|
@ -250,6 +254,14 @@ def readResult(frd_input):
|
||||||
nd1 = int(line[3:13])
|
nd1 = int(line[3:13])
|
||||||
nd2 = int(line[13:23])
|
nd2 = int(line[13:23])
|
||||||
elements_seg2[elem] = (nd1, nd2)
|
elements_seg2[elem] = (nd1, nd2)
|
||||||
|
elif elemType == 12:
|
||||||
|
# B32 CalculiX --> seg3 FreeCAD
|
||||||
|
# Also D element element number
|
||||||
|
# N1, N3 ,N2 Order in outpufile is 1,3,2
|
||||||
|
nd1 = int(line[3:13])
|
||||||
|
nd3 = int(line[13:23])
|
||||||
|
nd2 = int(line[23:33])
|
||||||
|
elements_seg3[elem] = (nd1, nd2, nd3)
|
||||||
|
|
||||||
# Check if we found new eigenmode
|
# Check if we found new eigenmode
|
||||||
if line[5:10] == "PMODE":
|
if line[5:10] == "PMODE":
|
||||||
|
@ -266,7 +278,7 @@ def readResult(frd_input):
|
||||||
mode_disp[elem] = FreeCAD.Vector(mode_disp_x, mode_disp_y, mode_disp_z)
|
mode_disp[elem] = FreeCAD.Vector(mode_disp_x, mode_disp_y, mode_disp_z)
|
||||||
if line[5:11] == "STRESS":
|
if line[5:11] == "STRESS":
|
||||||
mode_stress_found = True
|
mode_stress_found = True
|
||||||
# we found a displacement line in the frd file
|
# we found a stress line in the frd file
|
||||||
if mode_stress_found and (line[1:3] == "-1"):
|
if mode_stress_found and (line[1:3] == "-1"):
|
||||||
elem = int(line[4:13])
|
elem = int(line[4:13])
|
||||||
stress_1 = float(line[13:25])
|
stress_1 = float(line[13:25])
|
||||||
|
@ -276,6 +288,19 @@ def readResult(frd_input):
|
||||||
stress_5 = float(line[61:73])
|
stress_5 = float(line[61:73])
|
||||||
stress_6 = float(line[73:85])
|
stress_6 = float(line[73:85])
|
||||||
mode_stress[elem] = (stress_1, stress_2, stress_3, stress_4, stress_5, stress_6)
|
mode_stress[elem] = (stress_1, stress_2, stress_3, stress_4, stress_5, stress_6)
|
||||||
|
mode_stressv[elem] = FreeCAD.Vector(stress_1, stress_2, stress_3)
|
||||||
|
if line[5:13] == "TOSTRAIN":
|
||||||
|
mode_strain_found = True
|
||||||
|
# we found a strain line in the frd file
|
||||||
|
if mode_strain_found and (line[1:3] == "-1"):
|
||||||
|
elem = int(line[4:13])
|
||||||
|
strain_1 = float(line[13:25])
|
||||||
|
strain_2 = float(line[25:37])
|
||||||
|
strain_3 = float(line[37:49])
|
||||||
|
# strain_4 = float(line[49:61]) #Not used in vector
|
||||||
|
# strain_5 = float(line[61:73])
|
||||||
|
# strain_6 = float(line[73:85])
|
||||||
|
mode_strain[elem] = FreeCAD.Vector(strain_1, strain_2, strain_3)
|
||||||
# Check if we found a time step
|
# Check if we found a time step
|
||||||
if line[4:10] == "1PSTEP":
|
if line[4:10] == "1PSTEP":
|
||||||
mode_time_found = True
|
mode_time_found = True
|
||||||
|
@ -309,6 +334,8 @@ def readResult(frd_input):
|
||||||
mode_results['number'] = eigenmode
|
mode_results['number'] = eigenmode
|
||||||
mode_results['disp'] = mode_disp
|
mode_results['disp'] = mode_disp
|
||||||
mode_results['stress'] = mode_stress
|
mode_results['stress'] = mode_stress
|
||||||
|
mode_results['stressv'] = mode_stressv
|
||||||
|
mode_results['strainv'] = mode_strain
|
||||||
mode_results['temp'] = mode_temp
|
mode_results['temp'] = mode_temp
|
||||||
mode_results['time'] = timestep
|
mode_results['time'] = timestep
|
||||||
results.append(mode_results)
|
results.append(mode_results)
|
||||||
|
@ -322,6 +349,8 @@ def readResult(frd_input):
|
||||||
mode_results['number'] = eigenmode
|
mode_results['number'] = eigenmode
|
||||||
mode_results['disp'] = mode_disp
|
mode_results['disp'] = mode_disp
|
||||||
mode_results['stress'] = mode_stress
|
mode_results['stress'] = mode_stress
|
||||||
|
mode_results['stressv'] = mode_stressv
|
||||||
|
mode_results['strainv'] = mode_strain
|
||||||
mode_results['time'] = 0 # Dont return time if static
|
mode_results['time'] = 0 # Dont return time if static
|
||||||
results.append(mode_results)
|
results.append(mode_results)
|
||||||
mode_disp = {}
|
mode_disp = {}
|
||||||
|
@ -336,7 +365,7 @@ def readResult(frd_input):
|
||||||
return {'Nodes': nodes,
|
return {'Nodes': nodes,
|
||||||
'Hexa8Elem': elements_hexa8, 'Penta6Elem': elements_penta6, 'Tetra4Elem': elements_tetra4, 'Tetra10Elem': elements_tetra10,
|
'Hexa8Elem': elements_hexa8, 'Penta6Elem': elements_penta6, 'Tetra4Elem': elements_tetra4, 'Tetra10Elem': elements_tetra10,
|
||||||
'Penta15Elem': elements_penta15, 'Hexa20Elem': elements_hexa20, 'Tria3Elem': elements_tria3, 'Tria6Elem': elements_tria6,
|
'Penta15Elem': elements_penta15, 'Hexa20Elem': elements_hexa20, 'Tria3Elem': elements_tria3, 'Tria6Elem': elements_tria6,
|
||||||
'Quad4Elem': elements_quad4, 'Quad8Elem': elements_quad8, 'Seg2Elem': elements_seg2,
|
'Quad4Elem': elements_quad4, 'Quad8Elem': elements_quad8, 'Seg2Elem': elements_seg2, 'Seg3Elem': elements_seg3,
|
||||||
'Results': results}
|
'Results': results}
|
||||||
|
|
||||||
|
|
||||||
|
@ -421,6 +450,8 @@ def importFrd(filename, analysis=None, result_name_prefix=None):
|
||||||
break
|
break
|
||||||
|
|
||||||
disp = result_set['disp']
|
disp = result_set['disp']
|
||||||
|
stressv = result_set['stressv']
|
||||||
|
strainv = result_set['strainv']
|
||||||
no_of_values = len(disp)
|
no_of_values = len(disp)
|
||||||
displacement = []
|
displacement = []
|
||||||
for k, v in disp.iteritems():
|
for k, v in disp.iteritems():
|
||||||
|
@ -438,6 +469,8 @@ def importFrd(filename, analysis=None, result_name_prefix=None):
|
||||||
|
|
||||||
if len(disp) > 0:
|
if len(disp) > 0:
|
||||||
results.DisplacementVectors = map((lambda x: x * scale), disp.values())
|
results.DisplacementVectors = map((lambda x: x * scale), disp.values())
|
||||||
|
results.StressVectors = map((lambda x: x * scale), stressv.values())
|
||||||
|
results.StrainVectors = map((lambda x: x * scale), strainv.values())
|
||||||
results.NodeNumbers = disp.keys()
|
results.NodeNumbers = disp.keys()
|
||||||
if(mesh_object):
|
if(mesh_object):
|
||||||
results.Mesh = mesh_object
|
results.Mesh = mesh_object
|
||||||
|
|
|
@ -30,10 +30,10 @@ the module
|
||||||
'''
|
'''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
from PySide import QtGui
|
||||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||||
def translate(context, text):
|
def translate(context, text):
|
||||||
"convenience function for Qt translator"
|
"convenience function for Qt translator"
|
||||||
from PySide import QtGui
|
|
||||||
return QtGui.QApplication.translate(context, text, None, _encoding)
|
return QtGui.QApplication.translate(context, text, None, _encoding)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
def translate(context, text):
|
def translate(context, text):
|
||||||
|
|
|
@ -186,7 +186,7 @@ Intersection of this and a given list of topo shapes.
|
||||||
|
|
||||||
Supports:
|
Supports:
|
||||||
- Fuzzy Boolean operations (global tolerance for a Boolean operation)
|
- Fuzzy Boolean operations (global tolerance for a Boolean operation)
|
||||||
- Support of multiple arguments for a single Boolean operation (s1 AND (s2 OR s2))
|
- Support of multiple arguments for a single Boolean operation (s1 AND (s2 OR s3))
|
||||||
- Parallelization of Boolean Operations algorithm
|
- Parallelization of Boolean Operations algorithm
|
||||||
|
|
||||||
OCC 6.9.0 or later is required.</UserDocu>
|
OCC 6.9.0 or later is required.</UserDocu>
|
||||||
|
@ -203,7 +203,7 @@ Section of this and a given list of topo shapes.
|
||||||
|
|
||||||
Supports:
|
Supports:
|
||||||
- Fuzzy Boolean operations (global tolerance for a Boolean operation)
|
- Fuzzy Boolean operations (global tolerance for a Boolean operation)
|
||||||
- Support of multiple arguments for a single Boolean operation
|
- Support of multiple arguments for a single Boolean operation (s1 AND (s2 OR s3))
|
||||||
- Parallelization of Boolean Operations algorithm
|
- Parallelization of Boolean Operations algorithm
|
||||||
|
|
||||||
OCC 6.9.0 or later is required.</UserDocu>
|
OCC 6.9.0 or later is required.</UserDocu>
|
||||||
|
|
|
@ -37,16 +37,16 @@ if FreeCAD.GuiUp:
|
||||||
#-------------------------- translation-related code ----------------------------------------
|
#-------------------------- translation-related code ----------------------------------------
|
||||||
#(see forum thread "A new Part tool is being born... JoinFeatures!"
|
#(see forum thread "A new Part tool is being born... JoinFeatures!"
|
||||||
#http://forum.freecadweb.org/viewtopic.php?f=22&t=11112&start=30#p90239 )
|
#http://forum.freecadweb.org/viewtopic.php?f=22&t=11112&start=30#p90239 )
|
||||||
try:
|
try:
|
||||||
_fromUtf8 = QtCore.QString.fromUtf8
|
_fromUtf8 = QtCore.QString.fromUtf8
|
||||||
except Exception:
|
except Exception:
|
||||||
def _fromUtf8(s):
|
def _fromUtf8(s):
|
||||||
return s
|
return s
|
||||||
try:
|
try:
|
||||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||||
def _translate(context, text, disambig):
|
def _translate(context, text, disambig):
|
||||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
def _translate(context, text, disambig):
|
def _translate(context, text, disambig):
|
||||||
return QtGui.QApplication.translate(context, text, disambig)
|
return QtGui.QApplication.translate(context, text, disambig)
|
||||||
#--------------------------/translation-related code ----------------------------------------
|
#--------------------------/translation-related code ----------------------------------------
|
||||||
|
|
|
@ -99,7 +99,7 @@ public:
|
||||||
~TaskCheckGeometryResults();
|
~TaskCheckGeometryResults();
|
||||||
QString getShapeContentString();
|
QString getShapeContentString();
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void currentRowChanged (const QModelIndex ¤t, const QModelIndex &previous);
|
void currentRowChanged (const QModelIndex ¤t, const QModelIndex &previous);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -198,7 +198,7 @@ protected:
|
||||||
QPixmap *stepActive;
|
QPixmap *stepActive;
|
||||||
QPixmap *stepDone;
|
QPixmap *stepDone;
|
||||||
|
|
||||||
private slots:
|
private Q_SLOTS:
|
||||||
void selectionSlot(bool checked);
|
void selectionSlot(bool checked);
|
||||||
void buildPixmaps();
|
void buildPixmaps();
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ class DimensionControl : public QWidget
|
||||||
public:
|
public:
|
||||||
explicit DimensionControl(QWidget* parent);
|
explicit DimensionControl(QWidget* parent);
|
||||||
QPushButton *resetButton;
|
QPushButton *resetButton;
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void toggle3dSlot(bool);
|
void toggle3dSlot(bool);
|
||||||
void toggleDeltaSlot(bool);
|
void toggleDeltaSlot(bool);
|
||||||
void clearAllSlot(bool);
|
void clearAllSlot(bool);
|
||||||
|
@ -250,7 +250,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual void onSelectionChanged(const Gui::SelectionChanges& msg);
|
virtual void onSelectionChanged(const Gui::SelectionChanges& msg);
|
||||||
|
|
||||||
protected slots:
|
protected Q_SLOTS:
|
||||||
void selection1Slot(bool checked);
|
void selection1Slot(bool checked);
|
||||||
void selection2Slot(bool checked);
|
void selection2Slot(bool checked);
|
||||||
void resetDialogSlot(bool);
|
void resetDialogSlot(bool);
|
||||||
|
@ -326,7 +326,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual void onSelectionChanged(const Gui::SelectionChanges& msg);
|
virtual void onSelectionChanged(const Gui::SelectionChanges& msg);
|
||||||
|
|
||||||
protected slots:
|
protected Q_SLOTS:
|
||||||
void selection1Slot(bool checked);
|
void selection1Slot(bool checked);
|
||||||
void selection2Slot(bool checked);
|
void selection2Slot(bool checked);
|
||||||
void resetDialogSlot(bool);
|
void resetDialogSlot(bool);
|
||||||
|
|
|
@ -121,12 +121,12 @@ int ToolPy::PyInit(PyObject* args, PyObject* kwd)
|
||||||
else
|
else
|
||||||
getToolPtr()->Material = Tool::MATUNDEFINED;
|
getToolPtr()->Material = Tool::MATUNDEFINED;
|
||||||
|
|
||||||
getToolPtr()->Diameter = PyFloat_AsDouble(dia);
|
getToolPtr()->Diameter = dia ? PyFloat_AsDouble(dia) : 0.0;
|
||||||
getToolPtr()->LengthOffset = PyFloat_AsDouble(len);
|
getToolPtr()->LengthOffset = len ? PyFloat_AsDouble(len) : 0.0;
|
||||||
getToolPtr()->FlatRadius = PyFloat_AsDouble(fla);
|
getToolPtr()->FlatRadius = fla ? PyFloat_AsDouble(fla) : 0.0;
|
||||||
getToolPtr()->CornerRadius = PyFloat_AsDouble(cor);
|
getToolPtr()->CornerRadius = cor ? PyFloat_AsDouble(cor) : 0.0;
|
||||||
getToolPtr()->CuttingEdgeAngle = PyFloat_AsDouble(ang);
|
getToolPtr()->CuttingEdgeAngle = ang ? PyFloat_AsDouble(ang) : 0.0;
|
||||||
getToolPtr()->CuttingEdgeHeight = PyFloat_AsDouble(hei);
|
getToolPtr()->CuttingEdgeHeight = hei ? PyFloat_AsDouble(hei) : 0.0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ SET(PathScripts_SRCS
|
||||||
PathScripts/PathSimpleCopy.py
|
PathScripts/PathSimpleCopy.py
|
||||||
PathScripts/PathStock.py
|
PathScripts/PathStock.py
|
||||||
PathScripts/PathStop.py
|
PathScripts/PathStop.py
|
||||||
|
PathScripts/PathHelix.py
|
||||||
PathScripts/PathSurface.py
|
PathScripts/PathSurface.py
|
||||||
PathScripts/PathToolLenOffset.py
|
PathScripts/PathToolLenOffset.py
|
||||||
PathScripts/PathToolLibraryManager.py
|
PathScripts/PathToolLibraryManager.py
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
<file>icons/Path-FaceProfile.svg</file>
|
<file>icons/Path-FaceProfile.svg</file>
|
||||||
<file>icons/Path-Face.svg</file>
|
<file>icons/Path-Face.svg</file>
|
||||||
<file>icons/Path-Heights.svg</file>
|
<file>icons/Path-Heights.svg</file>
|
||||||
|
<file>icons/Path-Helix.svg</file>
|
||||||
<file>icons/Path-Hop.svg</file>
|
<file>icons/Path-Hop.svg</file>
|
||||||
<file>icons/Path-Inspect.svg</file>
|
<file>icons/Path-Inspect.svg</file>
|
||||||
<file>icons/Path-Job.svg</file>
|
<file>icons/Path-Job.svg</file>
|
||||||
|
|
548
src/Mod/Path/Gui/Resources/icons/Path-Helix.svg
Normal file
548
src/Mod/Path/Gui/Resources/icons/Path-Helix.svg
Normal file
|
@ -0,0 +1,548 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="64px"
|
||||||
|
height="64px"
|
||||||
|
id="svg2816"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="Path-Helix.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2818">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4513">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4515" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#999999;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4517" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3681">
|
||||||
|
<stop
|
||||||
|
id="stop3697"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#fff110;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#cf7008;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3685" />
|
||||||
|
</linearGradient>
|
||||||
|
<inkscape:perspective
|
||||||
|
sodipodi:type="inkscape:persp3d"
|
||||||
|
inkscape:vp_x="0 : 32 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_z="64 : 32 : 1"
|
||||||
|
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||||
|
id="perspective2824" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3622"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3622-9"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3653"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3675"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3697"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3720"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3742"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3764"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3785"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3806"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3806-3"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3835"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3614"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3614-8"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3643"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3643-3"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3672"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3672-5"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3701"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3701-8"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3746"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<pattern
|
||||||
|
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
|
||||||
|
id="pattern5231"
|
||||||
|
xlink:href="#Strips1_1-4"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective5224"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<pattern
|
||||||
|
inkscape:stockid="Stripes 1:1"
|
||||||
|
id="Strips1_1-4"
|
||||||
|
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||||
|
height="1"
|
||||||
|
width="2"
|
||||||
|
patternUnits="userSpaceOnUse"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<rect
|
||||||
|
id="rect4483-4"
|
||||||
|
height="2"
|
||||||
|
width="1"
|
||||||
|
y="-0.5"
|
||||||
|
x="0"
|
||||||
|
style="fill:black;stroke:none" />
|
||||||
|
</pattern>
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective5224-9"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<pattern
|
||||||
|
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
|
||||||
|
id="pattern5231-4"
|
||||||
|
xlink:href="#Strips1_1-6"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective5224-3"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<pattern
|
||||||
|
inkscape:stockid="Stripes 1:1"
|
||||||
|
id="Strips1_1-6"
|
||||||
|
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||||
|
height="1"
|
||||||
|
width="2"
|
||||||
|
patternUnits="userSpaceOnUse"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<rect
|
||||||
|
id="rect4483-0"
|
||||||
|
height="2"
|
||||||
|
width="1"
|
||||||
|
y="-0.5"
|
||||||
|
x="0"
|
||||||
|
style="fill:black;stroke:none" />
|
||||||
|
</pattern>
|
||||||
|
<pattern
|
||||||
|
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
|
||||||
|
id="pattern5296"
|
||||||
|
xlink:href="#pattern5231-3"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective5288"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<pattern
|
||||||
|
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
|
||||||
|
id="pattern5231-3"
|
||||||
|
xlink:href="#Strips1_1-4-3"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<pattern
|
||||||
|
inkscape:stockid="Stripes 1:1"
|
||||||
|
id="Strips1_1-4-3"
|
||||||
|
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||||
|
height="1"
|
||||||
|
width="2"
|
||||||
|
patternUnits="userSpaceOnUse"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<rect
|
||||||
|
id="rect4483-4-6"
|
||||||
|
height="2"
|
||||||
|
width="1"
|
||||||
|
y="-0.5"
|
||||||
|
x="0"
|
||||||
|
style="fill:black;stroke:none" />
|
||||||
|
</pattern>
|
||||||
|
<pattern
|
||||||
|
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
|
||||||
|
id="pattern5330"
|
||||||
|
xlink:href="#Strips1_1-9"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective5323"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<pattern
|
||||||
|
inkscape:stockid="Stripes 1:1"
|
||||||
|
id="Strips1_1-9"
|
||||||
|
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||||
|
height="1"
|
||||||
|
width="2"
|
||||||
|
patternUnits="userSpaceOnUse"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<rect
|
||||||
|
id="rect4483-3"
|
||||||
|
height="2"
|
||||||
|
width="1"
|
||||||
|
y="-0.5"
|
||||||
|
x="0"
|
||||||
|
style="fill:black;stroke:none" />
|
||||||
|
</pattern>
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective5361"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective5383"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective5411"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3681"
|
||||||
|
id="linearGradient3687"
|
||||||
|
x1="37.89756"
|
||||||
|
y1="41.087898"
|
||||||
|
x2="4.0605712"
|
||||||
|
y2="40.168594"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(127.27273,-51.272729)" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3681"
|
||||||
|
id="linearGradient3695"
|
||||||
|
x1="37.894287"
|
||||||
|
y1="40.484772"
|
||||||
|
x2="59.811455"
|
||||||
|
y2="43.558987"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(127.27273,-51.272729)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3681-3">
|
||||||
|
<stop
|
||||||
|
id="stop3697-3"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#fff110;stop-opacity:1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#cf7008;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3685-4" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
y2="43.558987"
|
||||||
|
x2="59.811455"
|
||||||
|
y1="40.484772"
|
||||||
|
x1="37.894287"
|
||||||
|
gradientTransform="translate(-37.00068,-20.487365)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient3608"
|
||||||
|
xlink:href="#linearGradient3681-3"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4513-2">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4515-2" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#999999;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4517-4" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
r="23.634638"
|
||||||
|
fy="7.9319997"
|
||||||
|
fx="32.151962"
|
||||||
|
cy="7.9319997"
|
||||||
|
cx="32.151962"
|
||||||
|
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient4538"
|
||||||
|
xlink:href="#linearGradient4513-2"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4513-1">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4515-8" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#999999;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4517-6" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
r="23.634638"
|
||||||
|
fy="7.9319997"
|
||||||
|
fx="32.151962"
|
||||||
|
cy="7.9319997"
|
||||||
|
cx="32.151962"
|
||||||
|
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient4538-6"
|
||||||
|
xlink:href="#linearGradient4513-1"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4513-1-3">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4515-8-7" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#999999;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4517-6-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
r="23.634638"
|
||||||
|
fy="35.869175"
|
||||||
|
fx="32.151962"
|
||||||
|
cy="35.869175"
|
||||||
|
cx="32.151962"
|
||||||
|
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient3069"
|
||||||
|
xlink:href="#linearGradient4513-1-3"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4513-1-2">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4515-8-6" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#999999;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4517-6-6" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
r="23.634638"
|
||||||
|
fy="35.869175"
|
||||||
|
fx="32.151962"
|
||||||
|
cy="35.869175"
|
||||||
|
cx="32.151962"
|
||||||
|
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient3102"
|
||||||
|
xlink:href="#linearGradient4513-1-2"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4513-1"
|
||||||
|
id="radialGradient3132"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.39497909,0,0,1.1841158,29.624484,3.2399607)"
|
||||||
|
cx="32.151962"
|
||||||
|
cy="27.950663"
|
||||||
|
fx="32.151962"
|
||||||
|
fy="27.950663"
|
||||||
|
r="23.634638" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="7.7781744"
|
||||||
|
inkscape:cx="-38.302485"
|
||||||
|
inkscape:cy="32.387915"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:grid-bbox="true"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1335"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4207"
|
||||||
|
dotted="true"
|
||||||
|
spacingx="0.5"
|
||||||
|
spacingy="0.5" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata2821">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#008b00;stroke-width:9;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 42,57 32,57 C 2,57 2,54.5 32,44.5 62,34.5 62,32 32,32 2,32 2,29.5 32,19.5 62,9.4999998 62,6.9999998 32,6.9999998 l -10,0"
|
||||||
|
id="path4379"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:transform-center-x="0.38569462"
|
||||||
|
inkscape:transform-center-y="-1.2856487" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient3132);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.97430003;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||||
|
d="m 33.328125,14.73446 0,17.46591 c 0,0 0,1.310757 0,8.59375 l 17.34375,-8.59375 0,-1.90625 0,-15.55966 z m 17.34375,22.55966 -17.34375,8.5625 0,7.03125 17.34375,-8.59375 z m 0,12.09375 -14.5625,7.21875 5.9375,3.90625 8.625,-5.71875 z"
|
||||||
|
id="rect4417"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccccccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 18 KiB |
|
@ -65,6 +65,7 @@ class PathWorkbench (Workbench):
|
||||||
from PathScripts import PathCustom
|
from PathScripts import PathCustom
|
||||||
from PathScripts import PathInspect
|
from PathScripts import PathInspect
|
||||||
from PathScripts import PathSimpleCopy
|
from PathScripts import PathSimpleCopy
|
||||||
|
from PathScripts import PathHelix
|
||||||
from PathScripts import PathEngrave
|
from PathScripts import PathEngrave
|
||||||
from PathScripts import PathSurface
|
from PathScripts import PathSurface
|
||||||
from PathScripts import PathSanity
|
from PathScripts import PathSanity
|
||||||
|
@ -80,7 +81,7 @@ class PathWorkbench (Workbench):
|
||||||
projcmdlist = ["Path_Job", "Path_Post", "Path_Inspect", "Path_Sanity"]
|
projcmdlist = ["Path_Job", "Path_Post", "Path_Inspect", "Path_Sanity"]
|
||||||
toolcmdlist = ["Path_ToolLibraryEdit", "Path_LoadTool"]
|
toolcmdlist = ["Path_ToolLibraryEdit", "Path_LoadTool"]
|
||||||
prepcmdlist = ["Path_Plane", "Path_Fixture", "Path_ToolLenOffset", "Path_Comment", "Path_Stop", "Path_FaceProfile", "Path_FacePocket", "Path_Custom", "Path_FromShape"]
|
prepcmdlist = ["Path_Plane", "Path_Fixture", "Path_ToolLenOffset", "Path_Comment", "Path_Stop", "Path_FaceProfile", "Path_FacePocket", "Path_Custom", "Path_FromShape"]
|
||||||
twodopcmdlist = ["Path_Contour", "Path_Profile", "Path_Profile_Edges", "Path_Pocket", "Path_Drilling", "Path_Engrave", "Path_MillFace"]
|
twodopcmdlist = ["Path_Contour", "Path_Profile", "Path_Profile_Edges", "Path_Pocket", "Path_Drilling", "Path_Engrave", "Path_MillFace", "Path_Helix"]
|
||||||
threedopcmdlist = ["Path_Surfacing"]
|
threedopcmdlist = ["Path_Surfacing"]
|
||||||
modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", "Path_SimpleCopy" ]
|
modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", "Path_SimpleCopy" ]
|
||||||
dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_HoldingTags"]
|
dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_HoldingTags"]
|
||||||
|
|
|
@ -275,7 +275,7 @@ class Chord (object):
|
||||||
return dir == 'Back' or dir == side
|
return dir == 'Back' or dir == side
|
||||||
|
|
||||||
def connectsTo(self, chord):
|
def connectsTo(self, chord):
|
||||||
return PathGeom.isRoughly(self.End, chord.Start)
|
return PathGeom.pointsCoincide(self.End, chord.Start)
|
||||||
|
|
||||||
class Bone:
|
class Bone:
|
||||||
def __init__(self, boneId, obj, lastCommand, inChord, outChord, smooth):
|
def __init__(self, boneId, obj, lastCommand, inChord, outChord, smooth):
|
||||||
|
|
818
src/Mod/Path/PathScripts/PathHelix.py
Normal file
818
src/Mod/Path/PathScripts/PathHelix.py
Normal file
|
@ -0,0 +1,818 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#***************************************************************************
|
||||||
|
#* *
|
||||||
|
#* Copyright (c) 2016 Lorenz Hüdepohl <dev@stellardeath.org> *
|
||||||
|
#* *
|
||||||
|
#* This program is free software; you can redistribute it and/or modify *
|
||||||
|
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||||
|
#* as published by the Free Software Foundation; either version 2 of *
|
||||||
|
#* the License, or (at your option) any later version. *
|
||||||
|
#* for detail see the LICENCE text file. *
|
||||||
|
#* *
|
||||||
|
#* This program is distributed in the hope that it will be useful, *
|
||||||
|
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
#* GNU Library General Public License for more details. *
|
||||||
|
#* *
|
||||||
|
#* You should have received a copy of the GNU Library General Public *
|
||||||
|
#* License along with this program; if not, write to the Free Software *
|
||||||
|
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
#* USA *
|
||||||
|
#* *
|
||||||
|
#***************************************************************************
|
||||||
|
|
||||||
|
import FreeCAD, Path
|
||||||
|
if FreeCAD.GuiUp:
|
||||||
|
import FreeCADGui
|
||||||
|
from PySide import QtCore, QtGui
|
||||||
|
from DraftTools import translate
|
||||||
|
|
||||||
|
from . import PathUtils
|
||||||
|
from .PathUtils import fmt
|
||||||
|
|
||||||
|
"""Helix Drill object and FreeCAD command"""
|
||||||
|
|
||||||
|
if FreeCAD.GuiUp:
|
||||||
|
try:
|
||||||
|
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||||
|
def translate(context, text, disambig=None):
|
||||||
|
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||||
|
except AttributeError:
|
||||||
|
def translate(context, text, disambig=None):
|
||||||
|
return QtGui.QApplication.translate(context, text, disambig)
|
||||||
|
else:
|
||||||
|
def translate(context, text, disambig=None):
|
||||||
|
return text
|
||||||
|
|
||||||
|
def z_cylinder(cyl):
|
||||||
|
""" Test if cylinder is aligned to z-Axis"""
|
||||||
|
if cyl.Surface.Axis.x != 0.0:
|
||||||
|
return False
|
||||||
|
if cyl.Surface.Axis.y != 0.0:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def connected(edge, face):
|
||||||
|
for otheredge in face.Edges:
|
||||||
|
if edge.isSame(otheredge):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def cylinders_in_selection():
|
||||||
|
from Part import Cylinder
|
||||||
|
selections = FreeCADGui.Selection.getSelectionEx()
|
||||||
|
|
||||||
|
cylinders = []
|
||||||
|
|
||||||
|
for selection in selections:
|
||||||
|
base = selection.Object
|
||||||
|
cylinders.append((base, []))
|
||||||
|
for feature in selection.SubElementNames:
|
||||||
|
subobj = getattr(base.Shape, feature)
|
||||||
|
if subobj.ShapeType =='Face':
|
||||||
|
if isinstance(subobj.Surface, Cylinder):
|
||||||
|
if z_cylinder(subobj):
|
||||||
|
cylinders[-1][1].append(feature)
|
||||||
|
|
||||||
|
return cylinders
|
||||||
|
|
||||||
|
|
||||||
|
def helix_cut(center, r_out, r_in, dr, zmax, zmin, dz, safe_z, tool_diameter, vfeed, hfeed, direction, startside):
|
||||||
|
"""
|
||||||
|
center: 2-tuple
|
||||||
|
(x0,y0) coordinates of center
|
||||||
|
r_out, r_in: floats
|
||||||
|
radial range, cut from outer radius r_out in layers of dr to inner radius r_in
|
||||||
|
zmax, zmin: floats
|
||||||
|
z-range, cut from zmax in layers of dz down to zmin
|
||||||
|
safe_z: float
|
||||||
|
safety layer height
|
||||||
|
tool_diameter: float
|
||||||
|
Width of tool
|
||||||
|
"""
|
||||||
|
from numpy import ceil, allclose, linspace
|
||||||
|
|
||||||
|
if (zmax <= zmin):
|
||||||
|
return
|
||||||
|
|
||||||
|
out = "(helix_cut <{0}, {1}>, {2})".format(center[0], center[1],
|
||||||
|
", ".join(map(str, (r_out, r_in, dr, zmax, zmin, dz, safe_z, tool_diameter, vfeed, hfeed, direction, startside))))
|
||||||
|
|
||||||
|
x0, y0 = center
|
||||||
|
nz = max(int(ceil((zmax - zmin)/dz)), 2)
|
||||||
|
zi = linspace(zmax, zmin, 2 * nz + 1)
|
||||||
|
|
||||||
|
if dr > tool_diameter:
|
||||||
|
FreeCAD.Console.PrintWarning("PathHelix: Warning, shortening dr to tool diameter!\n")
|
||||||
|
dr = tool_diameter
|
||||||
|
|
||||||
|
def xyz(x=None, y=None, z=None):
|
||||||
|
out = ""
|
||||||
|
if x is not None:
|
||||||
|
out += " X" + fmt(x)
|
||||||
|
if y is not None:
|
||||||
|
out += " Y" + fmt(y)
|
||||||
|
if z is not None:
|
||||||
|
out += " Z" + fmt(z)
|
||||||
|
return out
|
||||||
|
|
||||||
|
def rapid(x=None, y=None, z=None):
|
||||||
|
return "G0" + xyz(x,y,z) + "\n"
|
||||||
|
|
||||||
|
def F(f=None):
|
||||||
|
return (" F" + fmt(f) if f else "")
|
||||||
|
|
||||||
|
def feed(x=None, y=None, z=None, f=None):
|
||||||
|
return "G1" + xyz(x,y,z) + F(f) + "\n"
|
||||||
|
|
||||||
|
def arc(x,y,i,j,z,f):
|
||||||
|
if direction == "CW":
|
||||||
|
code = "G2"
|
||||||
|
elif direction == "CCW":
|
||||||
|
code = "G3"
|
||||||
|
return code + " I" + fmt(i) + " J" + fmt(j) + " X" + fmt(x) + " Y" + fmt(y) + " Z" + fmt(z) + F(f) + "\n"
|
||||||
|
|
||||||
|
def helix_cut_r(r):
|
||||||
|
out = ""
|
||||||
|
out += rapid(x=x0+r,y=y0)
|
||||||
|
out += rapid(z=zmax + tool_diameter)
|
||||||
|
out += feed(z=zmax,f=vfeed)
|
||||||
|
z=zmin
|
||||||
|
for i in range(1,nz+1):
|
||||||
|
out += arc(x0-r, y0, i=-r, j=0.0, z = zi[2*i-1], f=hfeed)
|
||||||
|
out += arc(x0+r, y0, i= r, j=0.0, z = zi[2*i], f=hfeed)
|
||||||
|
out += arc(x0-r, y0, i=-r, j=0.0, z = zmin, f=hfeed)
|
||||||
|
out += arc(x0+r, y0, i=r, j=0.0, z = zmin, f=hfeed)
|
||||||
|
out += feed(z=zmax + tool_diameter, f=vfeed)
|
||||||
|
out += rapid(z=safe_z)
|
||||||
|
return out
|
||||||
|
|
||||||
|
assert(r_out > 0.0)
|
||||||
|
assert(r_in >= 0.0)
|
||||||
|
|
||||||
|
msg = None
|
||||||
|
if r_out < 0.0:
|
||||||
|
msg = "r_out < 0"
|
||||||
|
elif r_in > 0 and r_out - r_in < tool_diameter:
|
||||||
|
msg = "r_out - r_in = {0} is < tool diameter of {1}".format(r_out - r_in, tool_diamater)
|
||||||
|
elif r_in == 0.0 and not r_out > tool_diameter/2.:
|
||||||
|
msg = "Cannot drill a hole of diameter {0} with a tool of diameter {1}".format(2 * r_out, tool_diameter)
|
||||||
|
elif not startside in ["inside", "outside"]:
|
||||||
|
msg = "Invalid value for parameter 'startside'"
|
||||||
|
|
||||||
|
if msg:
|
||||||
|
out += "(ERROR: Hole at {0}:".format((x0, y0, zmax)) + msg + ")\n"
|
||||||
|
FreeCAD.Console.PrintError("PathHelix: Hole at {0}:".format((x0, y0, zmax)) + msg + "\n")
|
||||||
|
return out
|
||||||
|
|
||||||
|
if r_in > 0:
|
||||||
|
out += "(annulus mode)\n"
|
||||||
|
r_out = r_out - tool_diameter/2
|
||||||
|
r_in = r_in + tool_diameter/2
|
||||||
|
if abs((r_out - r_in) / dr) < 1e-5:
|
||||||
|
radii = [(r_out + r_in)/2]
|
||||||
|
else:
|
||||||
|
nr = max(int(ceil((r_out - r_in)/dr)), 2)
|
||||||
|
radii = linspace(r_out, r_in, nr)
|
||||||
|
elif r_out <= 2 * dr:
|
||||||
|
out += "(single helix mode)\n"
|
||||||
|
radii = [r_out - tool_diameter/2]
|
||||||
|
assert(radii[0] > 0)
|
||||||
|
else:
|
||||||
|
out += "(full hole mode)\n"
|
||||||
|
r_out = r_out - tool_diameter/2
|
||||||
|
r_in = dr/2
|
||||||
|
|
||||||
|
nr = max(1 + int(ceil((r_out - r_in)/dr)), 2)
|
||||||
|
radii = linspace(r_out, r_in, nr)
|
||||||
|
assert(all(radii > 0))
|
||||||
|
|
||||||
|
if startside == "inside":
|
||||||
|
radii = radii[::-1]
|
||||||
|
|
||||||
|
for r in radii:
|
||||||
|
out += "(radius {0})\n".format(r)
|
||||||
|
out += helix_cut_r(r)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
def features_by_centers(base, features):
|
||||||
|
import scipy.spatial
|
||||||
|
features = sorted(features,
|
||||||
|
key = lambda feature : getattr(base.Shape, feature).Surface.Radius,
|
||||||
|
reverse = True)
|
||||||
|
|
||||||
|
coordinates = [(cylinder.Surface.Center.x, cylinder.Surface.Center.y) for cylinder in
|
||||||
|
[getattr(base.Shape, feature) for feature in features]]
|
||||||
|
|
||||||
|
tree = scipy.spatial.KDTree(coordinates)
|
||||||
|
seen = {}
|
||||||
|
|
||||||
|
by_centers = {}
|
||||||
|
for n, feature in enumerate(features):
|
||||||
|
if n in seen:
|
||||||
|
continue
|
||||||
|
seen[n] = True
|
||||||
|
|
||||||
|
cylinder = getattr(base.Shape, feature)
|
||||||
|
xc, yc, _ = cylinder.Surface.Center
|
||||||
|
by_centers[xc, yc] = {cylinder.Surface.Radius : feature}
|
||||||
|
|
||||||
|
for coord in tree.query_ball_point((xc, yc), cylinder.Surface.Radius):
|
||||||
|
seen[coord] = True
|
||||||
|
cylinder = getattr(base.Shape, features[coord])
|
||||||
|
by_centers[xc, yc][cylinder.Surface.Radius] = features[coord]
|
||||||
|
|
||||||
|
return by_centers
|
||||||
|
|
||||||
|
class ObjectPathHelix(object):
|
||||||
|
|
||||||
|
def __init__(self,obj):
|
||||||
|
# Basic
|
||||||
|
obj.addProperty("App::PropertyLinkSubList","Features","Path",translate("Features","Selected features for the drill operation"))
|
||||||
|
obj.addProperty("App::PropertyBool","Active","Path",translate("Active","Set to False to disable code generation"))
|
||||||
|
obj.addProperty("App::PropertyString","Comment","Path",translate("Comment","An optional comment for this profile, will appear in G-Code"))
|
||||||
|
|
||||||
|
# Helix specific
|
||||||
|
obj.addProperty("App::PropertyEnumeration", "Direction", "Helix Drill",
|
||||||
|
translate("Direction", "The direction of the circular cuts, clockwise (CW), or counter clockwise (CCW)"))
|
||||||
|
obj.Direction = ['CW','CCW']
|
||||||
|
|
||||||
|
obj.addProperty("App::PropertyEnumeration", "StartSide", "Helix Drill",
|
||||||
|
translate("Direction", "Start cutting from the inside or outside"))
|
||||||
|
obj.StartSide = ['inside','outside']
|
||||||
|
|
||||||
|
obj.addProperty("App::PropertyLength", "DeltaR", "Helix Drill",
|
||||||
|
translate("DeltaR", "Radius increment (must be smaller than tool diameter)"))
|
||||||
|
|
||||||
|
# Depth Properties
|
||||||
|
obj.addProperty("App::PropertyDistance", "Clearance", "Depths",
|
||||||
|
translate("Clearance","Safe distance above the top of the hole to which to retract the tool"))
|
||||||
|
obj.addProperty("App::PropertyLength", "StepDown", "Depths",
|
||||||
|
translate("StepDown","Incremental Step Down of Tool"))
|
||||||
|
obj.addProperty("App::PropertyBool","UseStartDepth","Depths",
|
||||||
|
translate("Use Start Depth","Set to True to manually specify a start depth"))
|
||||||
|
obj.addProperty("App::PropertyDistance", "StartDepth", "Depths",
|
||||||
|
translate("Start Depth","Starting Depth of Tool - first cut depth in Z"))
|
||||||
|
obj.addProperty("App::PropertyBool","UseFinalDepth","Depths",
|
||||||
|
translate("Use Final Depth","Set to True to manually specify a final depth"))
|
||||||
|
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depths",
|
||||||
|
translate("Final Depth","Final Depth of Tool - lowest value in Z"))
|
||||||
|
obj.addProperty("App::PropertyDistance", "ThroughDepth", "Depths",
|
||||||
|
translate("Through Depth","Add this amount of additional cutting depth to open-ended holes. Only used if UseFinalDepth is False"))
|
||||||
|
|
||||||
|
# The current tool number, read-only
|
||||||
|
# this is apparently used internally, to keep track of tool chagnes
|
||||||
|
obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("PathProfile","The current tool in use"))
|
||||||
|
obj.ToolNumber = (0,0,1000,1)
|
||||||
|
obj.setEditorMode('ToolNumber',1) #make this read only
|
||||||
|
|
||||||
|
obj.Proxy = self
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __setstate__(self,state):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def execute(self,obj):
|
||||||
|
from Part import Circle, Cylinder, Plane
|
||||||
|
from math import sqrt
|
||||||
|
|
||||||
|
output = '(helix cut operation'
|
||||||
|
if obj.Comment:
|
||||||
|
output += ', '+ str(obj.Comment)+')\n'
|
||||||
|
else:
|
||||||
|
output += ')\n'
|
||||||
|
|
||||||
|
if obj.Features:
|
||||||
|
if not obj.Active:
|
||||||
|
obj.Path = Path.Path("(helix cut operation inactive)")
|
||||||
|
if obj.ViewObject:
|
||||||
|
obj.ViewObject.Visibility = False
|
||||||
|
return
|
||||||
|
|
||||||
|
toolload = PathUtils.getLastToolLoad(obj)
|
||||||
|
|
||||||
|
if toolload is None or toolload.ToolNumber == 0:
|
||||||
|
FreeCAD.Console.PrintError("PathHelix: No tool selected for helix cut operation, insert a tool change operation first\n")
|
||||||
|
obj.Path = Path.Path("(ERROR: no tool selected for helix cut operation)")
|
||||||
|
return
|
||||||
|
|
||||||
|
tool = PathUtils.getTool(obj, toolload.ToolNumber)
|
||||||
|
|
||||||
|
zsafe = max(baseobj.Shape.BoundBox.ZMax for baseobj, features in obj.Features) + obj.Clearance.Value
|
||||||
|
output += "G0 Z" + fmt(zsafe)
|
||||||
|
|
||||||
|
drill_jobs = []
|
||||||
|
|
||||||
|
for base, features in obj.Features:
|
||||||
|
for center, by_radius in features_by_centers(base, features).items():
|
||||||
|
radii = sorted(by_radius.keys(), reverse=True)
|
||||||
|
cylinders = map(lambda radius: getattr(base.Shape, by_radius[radius]), radii)
|
||||||
|
zsafe = max(cyl.BoundBox.ZMax for cyl in cylinders) + obj.Clearance.Value
|
||||||
|
cur_z = cylinders[0].BoundBox.ZMax
|
||||||
|
jobs = []
|
||||||
|
|
||||||
|
for cylinder in cylinders:
|
||||||
|
# Find other edge of current cylinder
|
||||||
|
other_edge = None
|
||||||
|
for edge in cylinder.Edges:
|
||||||
|
if isinstance(edge.Curve, Circle) and edge.Curve.Center.z != cur_z:
|
||||||
|
other_edge = edge
|
||||||
|
break
|
||||||
|
|
||||||
|
next_z = other_edge.Curve.Center.z
|
||||||
|
dz = next_z - cur_z
|
||||||
|
r = cylinder.Surface.Radius
|
||||||
|
|
||||||
|
if dz < 0:
|
||||||
|
# This is a closed hole if the face connected to the current cylinder at next_z has
|
||||||
|
# the cylinder's edge as its OuterWire
|
||||||
|
closed = None
|
||||||
|
for face in base.Shape.Faces:
|
||||||
|
if connected(other_edge, face) and not face.isSame(cylinder.Faces[0]):
|
||||||
|
wire = face.OuterWire
|
||||||
|
if len(wire.Edges) == 1 and wire.Edges[0].isSame(other_edge):
|
||||||
|
closed = True
|
||||||
|
else:
|
||||||
|
closed = False
|
||||||
|
|
||||||
|
if closed is None:
|
||||||
|
raise Exception("Cannot determine if this cylinder is closed on the z = {0} side".format(next_z))
|
||||||
|
|
||||||
|
xc, yc, _ = cylinder.Surface.Center
|
||||||
|
jobs.append(dict(xc=xc, yc=yc, zmin=next_z, zmax=cur_z, r_out=r, r_in=0.0, closed=closed, zsafe=zsafe))
|
||||||
|
|
||||||
|
elif dz > 0:
|
||||||
|
new_jobs = []
|
||||||
|
for job in jobs:
|
||||||
|
if job["zmin"] < next_z < job["zmax"]:
|
||||||
|
# split this job
|
||||||
|
job1 = dict(job)
|
||||||
|
job2 = dict(job)
|
||||||
|
job1["zmin"] = next_z
|
||||||
|
job2["zmax"] = next_z
|
||||||
|
job2["r_in"] = r
|
||||||
|
new_jobs.append(job1)
|
||||||
|
new_jobs.append(job2)
|
||||||
|
else:
|
||||||
|
new_jobs.append(job)
|
||||||
|
jobs = new_jobs
|
||||||
|
else:
|
||||||
|
FreeCAD.Console.PrintError("PathHelix: Encountered cylinder with zero height\n")
|
||||||
|
break
|
||||||
|
|
||||||
|
cur_z = next_z
|
||||||
|
|
||||||
|
if obj.UseStartDepth:
|
||||||
|
jobs = [job for job in jobs if job["zmin"] < obj.StartDepth.Value]
|
||||||
|
if jobs:
|
||||||
|
jobs[0]["zmax"] = obj.StartDepth.Value
|
||||||
|
if obj.UseFinalDepth:
|
||||||
|
jobs = [job for job in jobs if job["zmax"] > obj.FinalDepth.Value]
|
||||||
|
if jobs:
|
||||||
|
jobs[-1]["zmin"] = obj.FinalDepth.Value
|
||||||
|
else:
|
||||||
|
if not jobs[-1]["closed"]:
|
||||||
|
jobs[-1]["zmin"] -= obj.ThroughDepth.Value
|
||||||
|
|
||||||
|
drill_jobs.extend(jobs)
|
||||||
|
|
||||||
|
for job in drill_jobs:
|
||||||
|
output += helix_cut((job["xc"], job["yc"]), job["r_out"], job["r_in"], obj.DeltaR.Value,
|
||||||
|
job["zmax"], job["zmin"], obj.StepDown.Value,
|
||||||
|
job["zsafe"], tool.Diameter,
|
||||||
|
toolload.VertFeed.Value, toolload.HorizFeed.Value, obj.Direction, obj.StartSide)
|
||||||
|
output += '\n'
|
||||||
|
|
||||||
|
obj.Path = Path.Path(output)
|
||||||
|
if obj.ViewObject:
|
||||||
|
obj.ViewObject.Visibility = True
|
||||||
|
|
||||||
|
taskpanels = {}
|
||||||
|
|
||||||
|
class ViewProviderPathHelix(object):
|
||||||
|
def __init__(self,vobj):
|
||||||
|
vobj.Proxy = self
|
||||||
|
|
||||||
|
def attach(self,vobj):
|
||||||
|
self.Object = vobj.Object
|
||||||
|
return
|
||||||
|
|
||||||
|
def getIcon(self):
|
||||||
|
return ":/icons/Path-Helix.svg"
|
||||||
|
|
||||||
|
def setEdit(self, vobj, mode=0):
|
||||||
|
FreeCADGui.Control.closeDialog()
|
||||||
|
taskpanel = TaskPanel(vobj.Object)
|
||||||
|
FreeCADGui.Control.showDialog(taskpanel)
|
||||||
|
taskpanels[0] = taskpanel
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __setstate__(self, state):
|
||||||
|
return None
|
||||||
|
|
||||||
|
class CommandPathHelix(object):
|
||||||
|
def GetResources(self):
|
||||||
|
return {'Pixmap' : 'Path-Helix',
|
||||||
|
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathHelix","PathHelix"),
|
||||||
|
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathHelix","Creates a helix cut from selected circles")}
|
||||||
|
|
||||||
|
def IsActive(self):
|
||||||
|
if FreeCAD.ActiveDocument is not None:
|
||||||
|
for o in FreeCAD.ActiveDocument.Objects:
|
||||||
|
if o.Name[:3] == "Job":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def Activated(self):
|
||||||
|
import FreeCADGui
|
||||||
|
import Path
|
||||||
|
from PathScripts import PathUtils
|
||||||
|
|
||||||
|
FreeCAD.ActiveDocument.openTransaction(translate("PathHelix","Create a helix cut"))
|
||||||
|
FreeCADGui.addModule("PathScripts.PathHelix")
|
||||||
|
|
||||||
|
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","PathHelix")
|
||||||
|
ObjectPathHelix(obj)
|
||||||
|
ViewProviderPathHelix(obj.ViewObject)
|
||||||
|
|
||||||
|
obj.Features = cylinders_in_selection()
|
||||||
|
obj.DeltaR = 1.0
|
||||||
|
|
||||||
|
toolLoad = PathUtils.getLastToolLoad(obj)
|
||||||
|
if toolLoad is not None:
|
||||||
|
obj.ToolNumber = toolLoad.ToolNumber
|
||||||
|
tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
|
||||||
|
if tool:
|
||||||
|
# start with 25% overlap
|
||||||
|
obj.DeltaR = tool.Diameter * 0.75
|
||||||
|
|
||||||
|
obj.Active = True
|
||||||
|
obj.Comment = ""
|
||||||
|
|
||||||
|
obj.Direction = "CW"
|
||||||
|
obj.StartSide = "inside"
|
||||||
|
|
||||||
|
obj.Clearance = 10.0
|
||||||
|
obj.StepDown = 1.0
|
||||||
|
obj.UseStartDepth = False
|
||||||
|
obj.StartDepth = 1.0
|
||||||
|
obj.UseFinalDepth = False
|
||||||
|
obj.FinalDepth = 0.0
|
||||||
|
obj.ThroughDepth = 0.0
|
||||||
|
|
||||||
|
PathUtils.addToJob(obj)
|
||||||
|
|
||||||
|
obj.ViewObject.startEditing()
|
||||||
|
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
|
||||||
|
def print_exceptions(func):
|
||||||
|
from functools import wraps
|
||||||
|
import traceback
|
||||||
|
import sys
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
try:
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
except:
|
||||||
|
ex_type, ex, tb = sys.exc_info()
|
||||||
|
FreeCAD.Console.PrintError("".join(traceback.format_exception(ex_type, ex, tb)) + "\n")
|
||||||
|
raise
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
def print_all_exceptions(cls):
|
||||||
|
for entry in dir(cls):
|
||||||
|
obj = getattr(cls, entry)
|
||||||
|
if not entry.startswith("__") and hasattr(obj, "__call__"):
|
||||||
|
setattr(cls, entry, print_exceptions(obj))
|
||||||
|
return cls
|
||||||
|
|
||||||
|
@print_all_exceptions
|
||||||
|
class TaskPanel(object):
|
||||||
|
|
||||||
|
def __init__(self, obj):
|
||||||
|
from Units import Quantity
|
||||||
|
self.obj = obj
|
||||||
|
|
||||||
|
ui = FreeCADGui.UiLoader()
|
||||||
|
layout = QtGui.QGridLayout()
|
||||||
|
|
||||||
|
headerStyle = "QLabel { font-weight: bold; font-size: large; }"
|
||||||
|
grayed_out = "background-color: #d0d0d0;"
|
||||||
|
|
||||||
|
self.previous_value = {}
|
||||||
|
|
||||||
|
def addWidget(widget):
|
||||||
|
row = layout.rowCount()
|
||||||
|
layout.addWidget(widget, row, 0, 1, 2)
|
||||||
|
|
||||||
|
def addWidgets(widget1, widget2):
|
||||||
|
row = layout.rowCount()
|
||||||
|
layout.addWidget(widget1, row, 0)
|
||||||
|
layout.addWidget(widget2, row, 1)
|
||||||
|
|
||||||
|
def heading(label):
|
||||||
|
heading = QtGui.QLabel(label)
|
||||||
|
heading.setStyleSheet(headerStyle)
|
||||||
|
addWidget(heading)
|
||||||
|
|
||||||
|
def addQuantity(property, labelstring, activator=None, max=None):
|
||||||
|
self.previous_value[property] = getattr(self.obj, property)
|
||||||
|
widget = ui.createWidget("Gui::InputField")
|
||||||
|
|
||||||
|
if activator:
|
||||||
|
self.previous_value[activator] = getattr(self.obj, activator)
|
||||||
|
currently_active = getattr(self.obj, activator)
|
||||||
|
label = QtGui.QCheckBox(labelstring)
|
||||||
|
|
||||||
|
def change(state):
|
||||||
|
setattr(self.obj, activator, label.isChecked())
|
||||||
|
if label.isChecked():
|
||||||
|
widget.setStyleSheet("")
|
||||||
|
else:
|
||||||
|
widget.setStyleSheet(grayed_out)
|
||||||
|
self.obj.Proxy.execute(self.obj)
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
|
||||||
|
label.stateChanged.connect(change)
|
||||||
|
label.setChecked(currently_active)
|
||||||
|
if not currently_active:
|
||||||
|
widget.setStyleSheet(grayed_out)
|
||||||
|
label.setToolTip(self.obj.getDocumentationOfProperty(activator))
|
||||||
|
else:
|
||||||
|
label = QtGui.QLabel(labelstring)
|
||||||
|
label.setToolTip(self.obj.getDocumentationOfProperty(property))
|
||||||
|
|
||||||
|
widget.setText(str(getattr(self.obj, property)))
|
||||||
|
widget.setToolTip(self.obj.getDocumentationOfProperty(property))
|
||||||
|
|
||||||
|
if max:
|
||||||
|
# cannot use widget.setMaximum() as apparently ui.createWidget()
|
||||||
|
# returns the object up-casted to QWidget.
|
||||||
|
widget.setProperty("maximum", max)
|
||||||
|
|
||||||
|
def change(quantity):
|
||||||
|
setattr(self.obj, property, quantity)
|
||||||
|
self.obj.Proxy.execute(self.obj)
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
|
||||||
|
QtCore.QObject.connect(widget, QtCore.SIGNAL("valueChanged(const Base::Quantity &)"), change)
|
||||||
|
|
||||||
|
addWidgets(label, widget)
|
||||||
|
return label, widget
|
||||||
|
|
||||||
|
def addCheckBox(property, label):
|
||||||
|
self.previous_value[property] = getattr(self.obj, property)
|
||||||
|
widget = QtGui.QCheckBox(label)
|
||||||
|
widget.setToolTip(self.obj.getDocumentationOfProperty(property))
|
||||||
|
|
||||||
|
def change(state):
|
||||||
|
setattr(self.obj, property, widget.isChecked())
|
||||||
|
self.obj.Proxy.execute(self.obj)
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
widget.stateChanged.connect(change)
|
||||||
|
|
||||||
|
widget.setChecked(getattr(self.obj, property))
|
||||||
|
addWidget(widget)
|
||||||
|
|
||||||
|
def addEnumeration(property, label, options):
|
||||||
|
self.previous_value[property] = getattr(self.obj, property)
|
||||||
|
label = QtGui.QLabel(label)
|
||||||
|
label.setToolTip(self.obj.getDocumentationOfProperty(property))
|
||||||
|
widget = QtGui.QComboBox()
|
||||||
|
widget.setToolTip(self.obj.getDocumentationOfProperty(property))
|
||||||
|
for option_label, option_value in options:
|
||||||
|
widget.addItem(option_label)
|
||||||
|
def change(index):
|
||||||
|
setattr(self.obj, property, options[index][1])
|
||||||
|
self.obj.Proxy.execute(self.obj)
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
widget.currentIndexChanged.connect(change)
|
||||||
|
addWidgets(label, widget)
|
||||||
|
|
||||||
|
self.featureTree = QtGui.QTreeWidget()
|
||||||
|
self.featureTree.setMinimumHeight(200)
|
||||||
|
self.featureTree.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
||||||
|
#self.featureTree.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
|
||||||
|
#self.featureTree.setDefaultDropAction(QtCore.Qt.MoveAction)
|
||||||
|
self.fillFeatureTree()
|
||||||
|
sm = self.featureTree.selectionModel()
|
||||||
|
sm.selectionChanged.connect(self.selectFeatures)
|
||||||
|
addWidget(self.featureTree)
|
||||||
|
self.featureTree.expandAll()
|
||||||
|
|
||||||
|
self.addButton = QtGui.QPushButton("Add holes")
|
||||||
|
self.addButton.clicked.connect(self.addCylinders)
|
||||||
|
|
||||||
|
self.delButton = QtGui.QPushButton("Delete")
|
||||||
|
self.delButton.clicked.connect(self.delCylinders)
|
||||||
|
|
||||||
|
addWidgets(self.addButton, self.delButton)
|
||||||
|
|
||||||
|
heading("Drill parameters")
|
||||||
|
addCheckBox("Active", "Operation is active")
|
||||||
|
tool = PathUtils.getTool(self.obj,self.obj.ToolNumber)
|
||||||
|
if not tool:
|
||||||
|
drmax = None
|
||||||
|
else:
|
||||||
|
drmax = tool.Diameter
|
||||||
|
addQuantity("DeltaR", "Step in Radius", max=drmax)
|
||||||
|
addQuantity("StepDown", "Step in Z")
|
||||||
|
addEnumeration("Direction", "Cut direction", [("Clockwise", "CW"), ("Counter-Clockwise", "CCW")])
|
||||||
|
addEnumeration("StartSide", "Start Side", [("Start from inside", "inside"), ("Start from outside", "outside")])
|
||||||
|
|
||||||
|
heading("Cutting Depths")
|
||||||
|
addQuantity("Clearance", "Clearance Distance")
|
||||||
|
addQuantity("StartDepth", "Absolute start height", "UseStartDepth")
|
||||||
|
|
||||||
|
fdcheckbox, fdinput = addQuantity("FinalDepth", "Absolute final height", "UseFinalDepth")
|
||||||
|
tdlabel, tdinput = addQuantity("ThroughDepth", "Extra drill depth\nfor open holes")
|
||||||
|
|
||||||
|
# make ThroughDepth and FinalDepth mutually exclusive
|
||||||
|
def fd_change(state):
|
||||||
|
if fdcheckbox.isChecked():
|
||||||
|
tdinput.setStyleSheet(grayed_out)
|
||||||
|
else:
|
||||||
|
tdinput.setStyleSheet("")
|
||||||
|
fdcheckbox.stateChanged.connect(fd_change)
|
||||||
|
|
||||||
|
def td_change(quantity):
|
||||||
|
fdcheckbox.setChecked(False)
|
||||||
|
QtCore.QObject.connect(tdinput, QtCore.SIGNAL("valueChanged(const Base::Quantity &)"), td_change)
|
||||||
|
|
||||||
|
if obj.UseFinalDepth:
|
||||||
|
tdinput.setStyleSheet(grayed_out)
|
||||||
|
|
||||||
|
# add
|
||||||
|
widget = QtGui.QWidget()
|
||||||
|
widget.setLayout(layout)
|
||||||
|
self.form = widget
|
||||||
|
|
||||||
|
def addCylinders(self):
|
||||||
|
features_per_base = {}
|
||||||
|
for base, features in self.obj.Features:
|
||||||
|
features_per_base[base] = list(set(features))
|
||||||
|
|
||||||
|
for base, features in cylinders_in_selection():
|
||||||
|
for feature in features:
|
||||||
|
if base in features_per_base:
|
||||||
|
if not feature in features_per_base[base]:
|
||||||
|
features_per_base[base].append(feature)
|
||||||
|
else:
|
||||||
|
features_per_base[base] = [feature]
|
||||||
|
|
||||||
|
self.obj.Features = list(features_per_base.items())
|
||||||
|
self.featureTree.clear()
|
||||||
|
self.fillFeatureTree()
|
||||||
|
self.featureTree.expandAll()
|
||||||
|
self.obj.Proxy.execute(self.obj)
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
|
||||||
|
def delCylinders(self):
|
||||||
|
del_features = []
|
||||||
|
|
||||||
|
def delete_feature(item, base=None):
|
||||||
|
kind, feature = item.data(0, QtCore.Qt.UserRole)
|
||||||
|
assert(kind == "feature")
|
||||||
|
|
||||||
|
if base is None:
|
||||||
|
base_item = item.parent().parent()
|
||||||
|
_, base = base_item.data(0, QtCore.Qt.UserRole)
|
||||||
|
|
||||||
|
del_features.append((base, feature))
|
||||||
|
item.parent().takeChild(item.parent().indexOfChild(item))
|
||||||
|
|
||||||
|
def delete_hole(item, base=None):
|
||||||
|
kind, center = item.data(0, QtCore.Qt.UserRole)
|
||||||
|
assert(kind == "hole")
|
||||||
|
|
||||||
|
if base is None:
|
||||||
|
base_item = item.parent()
|
||||||
|
_, base = base_item.data(0, QtCore.Qt.UserRole)
|
||||||
|
|
||||||
|
for i in reversed(range(item.childCount())):
|
||||||
|
delete_feature(item.child(i), base=base)
|
||||||
|
item.parent().takeChild(item.parent().indexOfChild(item))
|
||||||
|
|
||||||
|
def delete_base(item):
|
||||||
|
kind, base = item.data(0, QtCore.Qt.UserRole)
|
||||||
|
assert(kind == "base")
|
||||||
|
for i in reversed(range(item.childCount())):
|
||||||
|
delete_hole(item.child(i), base=base)
|
||||||
|
self.featureTree.takeTopLevelItem(self.featureTree.indexOfTopLevelItem(item))
|
||||||
|
|
||||||
|
for item in self.featureTree.selectedItems():
|
||||||
|
kind, info = item.data(0, QtCore.Qt.UserRole)
|
||||||
|
if kind == "base":
|
||||||
|
delete_base(item)
|
||||||
|
elif kind == "hole":
|
||||||
|
parent = item.parent()
|
||||||
|
delete_hole(item)
|
||||||
|
if parent.childCount() == 0:
|
||||||
|
self.featureTree.takeTopLevelItem(self.featureTree.indexOfTopLevelItem(parent))
|
||||||
|
elif kind =="feature":
|
||||||
|
parent = item.parent()
|
||||||
|
delete_feature(item)
|
||||||
|
if parent.childCount() == 0:
|
||||||
|
parent.parent().takeChild(parent.parent().indexOfChild(parent))
|
||||||
|
else:
|
||||||
|
raise Exception("No such item kind: {0}".format(kind))
|
||||||
|
|
||||||
|
for base, features in cylinders_in_selection():
|
||||||
|
for feature in features:
|
||||||
|
del_features.append((base, feature))
|
||||||
|
|
||||||
|
new_features = []
|
||||||
|
for obj, features in self.obj.Features:
|
||||||
|
for feature in features:
|
||||||
|
if (obj, feature) not in del_features:
|
||||||
|
new_features.append((obj, feature))
|
||||||
|
|
||||||
|
self.obj.Features = new_features
|
||||||
|
self.obj.Proxy.execute(self.obj)
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
|
||||||
|
def fillFeatureTree(self):
|
||||||
|
for base, features in self.obj.Features:
|
||||||
|
base_item = QtGui.QTreeWidgetItem()
|
||||||
|
base_item.setText(0, base.Name)
|
||||||
|
base_item.setData(0, QtCore.Qt.UserRole, ("base", base))
|
||||||
|
self.featureTree.addTopLevelItem(base_item)
|
||||||
|
for center, by_radius in features_by_centers(base, features).items():
|
||||||
|
hole_item = QtGui.QTreeWidgetItem()
|
||||||
|
hole_item.setText(0, "Hole at ({0[0]:.2f}, {0[1]:.2f})".format(center))
|
||||||
|
hole_item.setData(0, QtCore.Qt.UserRole, ("hole", center))
|
||||||
|
base_item.addChild(hole_item)
|
||||||
|
for radius in sorted(by_radius.keys(), reverse=True):
|
||||||
|
feature = by_radius[radius]
|
||||||
|
cylinder = getattr(base.Shape, feature)
|
||||||
|
cyl_item = QtGui.QTreeWidgetItem()
|
||||||
|
cyl_item.setText(0, "Diameter {0:.2f}, {1}".format(2 * cylinder.Surface.Radius, feature))
|
||||||
|
cyl_item.setData(0, QtCore.Qt.UserRole, ("feature", feature))
|
||||||
|
hole_item.addChild(cyl_item)
|
||||||
|
|
||||||
|
def selectFeatures(self, selected, deselected):
|
||||||
|
FreeCADGui.Selection.clearSelection()
|
||||||
|
def select_feature(item, base=None):
|
||||||
|
kind, feature = item.data(0, QtCore.Qt.UserRole)
|
||||||
|
assert(kind == "feature")
|
||||||
|
|
||||||
|
if base is None:
|
||||||
|
base_item = item.parent().parent()
|
||||||
|
_, base = base_item.data(0, QtCore.Qt.UserRole)
|
||||||
|
|
||||||
|
FreeCADGui.Selection.addSelection(base, feature)
|
||||||
|
|
||||||
|
def select_hole(item, base=None):
|
||||||
|
kind, center = item.data(0, QtCore.Qt.UserRole)
|
||||||
|
assert(kind == "hole")
|
||||||
|
|
||||||
|
if base is None:
|
||||||
|
base_item = item.parent()
|
||||||
|
_, base = base_item.data(0, QtCore.Qt.UserRole)
|
||||||
|
|
||||||
|
for i in range(item.childCount()):
|
||||||
|
select_feature(item.child(i), base=base)
|
||||||
|
|
||||||
|
def select_base(item):
|
||||||
|
kind, base = item.data(0, QtCore.Qt.UserRole)
|
||||||
|
assert(kind == "base")
|
||||||
|
|
||||||
|
for i in range(item.childCount()):
|
||||||
|
select_hole(item.child(i), base=base)
|
||||||
|
|
||||||
|
for item in self.featureTree.selectedItems():
|
||||||
|
kind, info = item.data(0, QtCore.Qt.UserRole)
|
||||||
|
|
||||||
|
if kind == "base":
|
||||||
|
select_base(item)
|
||||||
|
elif kind == "hole":
|
||||||
|
select_hole(item)
|
||||||
|
elif kind == "feature":
|
||||||
|
select_feature(item)
|
||||||
|
|
||||||
|
def needsFullSpace(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
FreeCADGui.ActiveDocument.resetEdit()
|
||||||
|
FreeCADGui.Control.closeDialog()
|
||||||
|
|
||||||
|
def reject(self):
|
||||||
|
for property in self.previous_value:
|
||||||
|
setattr(self.obj, property, self.previous_value[property])
|
||||||
|
self.obj.Proxy.execute(self.obj)
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
FreeCADGui.ActiveDocument.resetEdit()
|
||||||
|
FreeCADGui.Control.closeDialog()
|
||||||
|
|
||||||
|
if FreeCAD.GuiUp:
|
||||||
|
import FreeCADGui
|
||||||
|
FreeCADGui.addCommand('Path_Helix',CommandPathHelix())
|
|
@ -29,6 +29,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Base/Tools.h>
|
#include <Base/Tools.h>
|
||||||
|
#include <Base/Tools2D.h>
|
||||||
#include <App/Application.h>
|
#include <App/Application.h>
|
||||||
#include <Gui/Application.h>
|
#include <Gui/Application.h>
|
||||||
#include <Gui/Document.h>
|
#include <Gui/Document.h>
|
||||||
|
@ -3252,10 +3253,29 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
||||||
Base::Vector3d p1b = lineSeg1->getEndPoint();
|
Base::Vector3d p1b = lineSeg1->getEndPoint();
|
||||||
Base::Vector3d p2a = lineSeg2->getStartPoint();
|
Base::Vector3d p2a = lineSeg2->getStartPoint();
|
||||||
Base::Vector3d p2b = lineSeg2->getEndPoint();
|
Base::Vector3d p2b = lineSeg2->getEndPoint();
|
||||||
|
|
||||||
|
// Get the intersection point in 2d of the two lines if possible
|
||||||
|
Base::Line2d line1(Base::Vector2d(p1a.x, p1a.y), Base::Vector2d(p1b.x, p1b.y));
|
||||||
|
Base::Line2d line2(Base::Vector2d(p2a.x, p2a.y), Base::Vector2d(p2b.x, p2b.y));
|
||||||
|
Base::Vector2d s;
|
||||||
|
if (line1.Intersect(line2, s)) {
|
||||||
|
// get the end points of the line segments that are closest to the intersection point
|
||||||
|
Base::Vector3d s3d(s.x, s.y, p1a.z);
|
||||||
|
if (Base::DistanceP2(s3d, p1a) < Base::DistanceP2(s3d, p1b))
|
||||||
|
PosId1 = Sketcher::start;
|
||||||
|
else
|
||||||
|
PosId1 = Sketcher::end;
|
||||||
|
if (Base::DistanceP2(s3d, p2a) < Base::DistanceP2(s3d, p2b))
|
||||||
|
PosId2 = Sketcher::start;
|
||||||
|
else
|
||||||
|
PosId2 = Sketcher::end;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// if all points are collinear
|
||||||
double length = DBL_MAX;
|
double length = DBL_MAX;
|
||||||
for (int i=0; i <= 1; i++) {
|
for (int i=0; i <= 1; i++) {
|
||||||
for (int j=0; j <= 1; j++) {
|
for (int j=0; j <= 1; j++) {
|
||||||
double tmp = ((j?p2a:p2b)-(i?p1a:p1b)).Length();
|
double tmp = Base::DistanceP2((j?p2a:p2b), (i?p1a:p1b));
|
||||||
if (tmp < length) {
|
if (tmp < length) {
|
||||||
length = tmp;
|
length = tmp;
|
||||||
PosId1 = i ? Sketcher::start : Sketcher::end;
|
PosId1 = i ? Sketcher::start : Sketcher::end;
|
||||||
|
@ -3263,6 +3283,7 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Base::Vector3d dir1 = ((PosId1 == Sketcher::start) ? 1. : -1.) *
|
Base::Vector3d dir1 = ((PosId1 == Sketcher::start) ? 1. : -1.) *
|
||||||
(lineSeg1->getEndPoint()-lineSeg1->getStartPoint());
|
(lineSeg1->getEndPoint()-lineSeg1->getStartPoint());
|
||||||
|
@ -3280,8 +3301,8 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double ActAngle = atan2(-dir1.y*dir2.x+dir1.x*dir2.y,
|
double ActAngle = atan2(dir1.x*dir2.y-dir1.y*dir2.x,
|
||||||
dir1.x*dir2.x+dir1.y*dir2.y);
|
dir1.y*dir2.y+dir1.x*dir2.x);
|
||||||
if (ActAngle < 0) {
|
if (ActAngle < 0) {
|
||||||
ActAngle *= -1;
|
ActAngle *= -1;
|
||||||
std::swap(GeoId1,GeoId2);
|
std::swap(GeoId1,GeoId2);
|
||||||
|
|
|
@ -181,7 +181,7 @@ signals:
|
||||||
void clicked();
|
void clicked();
|
||||||
void selected();
|
void selected();
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void setColor(const QColor &color, const QString &text = QString());
|
void setColor(const QColor &color, const QString &text = QString());
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -224,10 +224,10 @@ signals:
|
||||||
void selected(const QColor &);
|
void selected(const QColor &);
|
||||||
void hid();
|
void hid();
|
||||||
|
|
||||||
public slots:
|
public Q_SLOTS:
|
||||||
void getColorFromDialog();
|
void getColorFromDialog();
|
||||||
|
|
||||||
protected slots:
|
protected Q_SLOTS:
|
||||||
void updateSelected();
|
void updateSelected();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -434,7 +434,7 @@ void QtColorPicker::setStandardColors()
|
||||||
void QtColorPicker::setCurrentColor(const QColor &color)
|
void QtColorPicker::setCurrentColor(const QColor &color)
|
||||||
{
|
{
|
||||||
if (color.isValid() && col == color) {
|
if (color.isValid() && col == color) {
|
||||||
emit colorSet(color);
|
Q_EMIT colorSet(color);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (col == color || !color.isValid())
|
if (col == color || !color.isValid())
|
||||||
|
@ -457,8 +457,8 @@ void QtColorPicker::setCurrentColor(const QColor &color)
|
||||||
repaint();
|
repaint();
|
||||||
|
|
||||||
item->setSelected(true);
|
item->setSelected(true);
|
||||||
emit colorChanged(color);
|
Q_EMIT colorChanged(color);
|
||||||
emit colorSet(color);
|
Q_EMIT colorSet(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -679,7 +679,7 @@ void ColorPickerPopup::updateSelected()
|
||||||
if (sender() && sender()->inherits("ColorPickerItem")) {
|
if (sender() && sender()->inherits("ColorPickerItem")) {
|
||||||
ColorPickerItem *item = (ColorPickerItem *)sender();
|
ColorPickerItem *item = (ColorPickerItem *)sender();
|
||||||
lastSel = item->color();
|
lastSel = item->color();
|
||||||
emit selected(item->color());
|
Q_EMIT selected(item->color());
|
||||||
}
|
}
|
||||||
|
|
||||||
hide();
|
hide();
|
||||||
|
@ -764,7 +764,7 @@ void ColorPickerPopup::keyPressEvent(QKeyEvent *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSel = wi->color();
|
lastSel = wi->color();
|
||||||
emit selected(wi->color());
|
Q_EMIT selected(wi->color());
|
||||||
hide();
|
hide();
|
||||||
} else if (w && w->inherits("QPushButton")) {
|
} else if (w && w->inherits("QPushButton")) {
|
||||||
ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
|
ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
|
||||||
|
@ -784,7 +784,7 @@ void ColorPickerPopup::keyPressEvent(QKeyEvent *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSel = wi->color();
|
lastSel = wi->color();
|
||||||
emit selected(wi->color());
|
Q_EMIT selected(wi->color());
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -811,7 +811,7 @@ void ColorPickerPopup::hideEvent(QHideEvent *e)
|
||||||
|
|
||||||
setFocus();
|
setFocus();
|
||||||
|
|
||||||
emit hid();
|
Q_EMIT hid();
|
||||||
QFrame::hideEvent(e);
|
QFrame::hideEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,7 +906,7 @@ void ColorPickerPopup::getColorFromDialog()
|
||||||
//QColor col = QColor::fromRgba(rgb);
|
//QColor col = QColor::fromRgba(rgb);
|
||||||
insertColor(col, tr("Custom"), -1);
|
insertColor(col, tr("Custom"), -1);
|
||||||
lastSel = col;
|
lastSel = col;
|
||||||
emit selected(col);
|
Q_EMIT selected(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorPickerPopup::setLastSel(const QColor & col) { lastSel = col; }
|
void ColorPickerPopup::setLastSel(const QColor & col) { lastSel = col; }
|
||||||
|
@ -994,7 +994,7 @@ void ColorPickerItem::mouseMoveEvent(QMouseEvent *)
|
||||||
void ColorPickerItem::mouseReleaseEvent(QMouseEvent *)
|
void ColorPickerItem::mouseReleaseEvent(QMouseEvent *)
|
||||||
{
|
{
|
||||||
sel = true;
|
sel = true;
|
||||||
emit selected();
|
Q_EMIT selected();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1062,7 +1062,7 @@ void ColorPickerButton::mouseReleaseEvent(QMouseEvent *)
|
||||||
{
|
{
|
||||||
setFrameShadow(Raised);
|
setFrameShadow(Raised);
|
||||||
repaint();
|
repaint();
|
||||||
emit clicked();
|
Q_EMIT clicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1096,7 +1096,7 @@ void ColorPickerButton::keyReleaseEvent(QKeyEvent *e)
|
||||||
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return) {
|
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return) {
|
||||||
setFrameShadow(Raised);
|
setFrameShadow(Raised);
|
||||||
repaint();
|
repaint();
|
||||||
emit clicked();
|
Q_EMIT clicked();
|
||||||
} else {
|
} else {
|
||||||
QFrame::keyReleaseEvent(e);
|
QFrame::keyReleaseEvent(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,7 @@ void FileChooser::chooseFile()
|
||||||
|
|
||||||
if (!fn.isEmpty()) {
|
if (!fn.isEmpty()) {
|
||||||
lineEdit->setText(fn);
|
lineEdit->setText(fn);
|
||||||
emit fileNameSelected(fn);
|
Q_EMIT fileNameSelected(fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,7 +1032,7 @@ void ColorButton::onChooseColor()
|
||||||
if ( c.isValid() )
|
if ( c.isValid() )
|
||||||
{
|
{
|
||||||
setColor( c );
|
setColor( c );
|
||||||
emit changed();
|
Q_EMIT changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,7 @@ void Wizard::setCurrentIndex(int index)
|
||||||
textLabel->setText(stackWidget->currentWidget()->windowTitle());
|
textLabel->setText(stackWidget->currentWidget()->windowTitle());
|
||||||
_backButton->setEnabled(index > 0);
|
_backButton->setEnabled(index > 0);
|
||||||
_nextButton->setEnabled(index < count()-1);
|
_nextButton->setEnabled(index < count()-1);
|
||||||
emit currentIndexChanged(index);
|
Q_EMIT currentIndexChanged(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ void Wizard::setPageTitle(QString const &newTitle)
|
||||||
{
|
{
|
||||||
stackWidget->currentWidget()->setWindowTitle(newTitle);
|
stackWidget->currentWidget()->setWindowTitle(newTitle);
|
||||||
textLabel->setText(newTitle);
|
textLabel->setText(newTitle);
|
||||||
emit pageTitleChanged(newTitle);
|
Q_EMIT pageTitleChanged(newTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
WizardExtension::WizardExtension(Wizard *widget, QObject *parent)
|
WizardExtension::WizardExtension(Wizard *widget, QObject *parent)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user