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().Log("%s\n", e.getStackTrace().c_str());
|
||||
Base::Console().Error("%s\n", e.getStackTrace().c_str());
|
||||
if (!d->startingUp) {
|
||||
wc.restoreCursor();
|
||||
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;
|
||||
|
||||
#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);
|
||||
const QChar *msg = qmsg.unicode();
|
||||
#ifdef FC_DEBUG
|
||||
switch (type)
|
||||
{
|
||||
|
@ -1290,26 +1289,26 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt
|
|||
case QtInfoMsg:
|
||||
#endif
|
||||
case QtDebugMsg:
|
||||
Base::Console().Message("%s\n", msg);
|
||||
Base::Console().Message("%s\n", msg.toUtf8().constData());
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
Base::Console().Warning("%s\n", msg);
|
||||
Base::Console().Warning("%s\n", msg.toUtf8().constData());
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
Base::Console().Error("%s\n", msg);
|
||||
Base::Console().Error("%s\n", msg.toUtf8().constData());
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
Base::Console().Error("%s\n", msg);
|
||||
Base::Console().Error("%s\n", msg.toUtf8().constData());
|
||||
abort(); // deliberately core dump
|
||||
}
|
||||
#ifdef FC_OS_WIN32
|
||||
if (old_qtmsg_handler)
|
||||
(*old_qtmsg_handler)(type, context, qmsg);
|
||||
(*old_qtmsg_handler)(type, context, msg);
|
||||
#endif
|
||||
#else
|
||||
// do not stress user with Qt internals but write to log file if enabled
|
||||
Q_UNUSED(type);
|
||||
Base::Console().Log("%s\n", msg);
|
||||
Base::Console().Log("%s\n", msg.toUtf8().constData());
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -69,7 +69,7 @@ public:
|
|||
void pause();
|
||||
void resume();
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void readClient();
|
||||
void discardClient();
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ void TaskHeader::leaveEvent ( QEvent * /*event*/ )
|
|||
void TaskHeader::fold()
|
||||
{
|
||||
if (myExpandable) {
|
||||
emit activated();
|
||||
Q_EMIT activated();
|
||||
// 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.
|
||||
#if 0
|
||||
|
@ -254,7 +254,7 @@ void TaskHeader::changeIcons()
|
|||
void TaskHeader::mouseReleaseEvent ( QMouseEvent * event )
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
emit activated();
|
||||
Q_EMIT activated();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
|
||||
QMenu * getMenu(void) const;
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void changeRenderMode(QAction * action);
|
||||
void changeStereoMode(QAction * action);
|
||||
void changeTransparencyType(QAction * action);
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
SensorManager(void);
|
||||
~SensorManager();
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void idleTimeout(void);
|
||||
void delayTimeout(void);
|
||||
void timerQueueTimeout(void);
|
||||
|
|
|
@ -70,7 +70,7 @@ SignalThread::run(void)
|
|||
// just wait, and trigger every time we receive a signal
|
||||
this->waitcond.wait(&this->mutex);
|
||||
if (!this->isstopped) {
|
||||
emit triggerSignal();
|
||||
Q_EMIT triggerSignal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -162,10 +162,10 @@ void iisIconLabel::mousePressEvent ( QMouseEvent * event )
|
|||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
m_pressed = true;
|
||||
emit pressed();
|
||||
Q_EMIT pressed();
|
||||
} else
|
||||
if (event->button() == Qt::RightButton)
|
||||
emit contextMenu();
|
||||
Q_EMIT contextMenu();
|
||||
|
||||
update();
|
||||
}
|
||||
|
@ -174,11 +174,11 @@ void iisIconLabel::mouseReleaseEvent ( QMouseEvent * event )
|
|||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
m_pressed = false;
|
||||
emit released();
|
||||
Q_EMIT released();
|
||||
|
||||
if (rect().contains( event->pos() )) {
|
||||
emit clicked();
|
||||
emit activated();
|
||||
Q_EMIT clicked();
|
||||
Q_EMIT activated();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ void iisIconLabel::keyPressEvent ( QKeyEvent * event )
|
|||
switch (event->key()) {
|
||||
case Qt::Key_Space:
|
||||
case Qt::Key_Return:
|
||||
emit activated();
|
||||
Q_EMIT activated();
|
||||
break;
|
||||
|
||||
default:;
|
||||
|
|
|
@ -165,7 +165,7 @@ void iisTaskHeader::leaveEvent ( QEvent * /*event*/ )
|
|||
void iisTaskHeader::fold()
|
||||
{
|
||||
if (myExpandable) {
|
||||
emit activated();
|
||||
Q_EMIT activated();
|
||||
|
||||
m_fold = !m_fold;
|
||||
changeIcons();
|
||||
|
@ -195,7 +195,7 @@ void iisTaskHeader::changeIcons()
|
|||
void iisTaskHeader::mouseReleaseEvent ( QMouseEvent * event )
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
emit activated();
|
||||
Q_EMIT activated();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -222,46 +222,6 @@
|
|||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
||||
<item>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>522</width>
|
||||
<height>462</height>
|
||||
<height>473</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -153,6 +153,46 @@ such as "Arial:Bold"</string>
|
|||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
|
@ -364,7 +404,7 @@ such as "Arial:Bold"</string>
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser" native="true">
|
||||
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
|
@ -405,6 +445,21 @@ such as "Arial:Bold"</string>
|
|||
<layoutdefault spacing="6" margin="11"/>
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
<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>
|
||||
<class>Gui::PrefCheckBox</class>
|
||||
<extends>QCheckBox</extends>
|
||||
|
@ -425,16 +480,6 @@ such as "Arial:Bold"</string>
|
|||
<extends>QDoubleSpinBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</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>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
|
@ -776,6 +776,8 @@ non-parametric curve"""
|
|||
warn('polygon fallback on %s' %spline)
|
||||
return drawSplineIterpolation(controlpoints,closed=closed,\
|
||||
forceShape=forceShape,alwaysDiscretize=True)
|
||||
if fitpoints and not(controlpoints):
|
||||
return drawSplineIterpolation(fitpoints,closed=closed,forceShape=forceShape)
|
||||
try:
|
||||
bspline=Part.BSplineCurve()
|
||||
bspline.buildFromPolesMultsKnots(poles=controlpoints,mults=multvector,\
|
||||
|
|
|
@ -71,6 +71,7 @@ SET(FemScripts_SRCS
|
|||
_CommandMaterial.py
|
||||
_CommandMeshGmshFromShape.py
|
||||
_CommandMeshNetgenFromShape.py
|
||||
_CommandMeshGroup.py
|
||||
_CommandMeshRegion.py
|
||||
_CommandPrintMeshInfo.py
|
||||
_CommandPurgeResults.py
|
||||
|
@ -83,6 +84,7 @@ SET(FemScripts_SRCS
|
|||
_FemConstraintSelfWeight.py
|
||||
_FemMaterialMechanicalNonlinear.py
|
||||
_FemMeshGmsh.py
|
||||
_FemMeshGroup.py
|
||||
_FemMeshRegion.py
|
||||
_FemShellThickness.py
|
||||
_FemSolverCalculix.py
|
||||
|
@ -90,6 +92,7 @@ SET(FemScripts_SRCS
|
|||
_FemMaterial.py
|
||||
_TaskPanelFemBeamSection.py
|
||||
_TaskPanelFemMeshGmsh.py
|
||||
_TaskPanelFemMeshGroup.py
|
||||
_TaskPanelFemMeshRegion.py
|
||||
_TaskPanelFemShellThickness.py
|
||||
_TaskPanelFemSolverCalculix.py
|
||||
|
@ -99,6 +102,7 @@ SET(FemScripts_SRCS
|
|||
_ViewProviderFemConstraintSelfWeight.py
|
||||
_ViewProviderFemMaterialMechanicalNonlinear.py
|
||||
_ViewProviderFemMeshGmsh.py
|
||||
_ViewProviderFemMeshGroup.py
|
||||
_ViewProviderFemMeshRegion.py
|
||||
_ViewProviderFemShellThickness.py
|
||||
_ViewProviderFemSolverCalculix.py
|
||||
|
@ -122,6 +126,7 @@ SET(FemScripts_SRCS
|
|||
FemMaterialMechanicalNonlinear.py
|
||||
FemMesh2Mesh.py
|
||||
FemMeshGmsh.py
|
||||
FemMeshGroup.py
|
||||
FemMeshRegion.py
|
||||
FemMeshTools.py
|
||||
FemShellThickness.py
|
||||
|
@ -136,6 +141,7 @@ SET(FemScripts_SRCS
|
|||
z88DispReader.py
|
||||
TaskPanelFemBeamSection.ui
|
||||
TaskPanelFemMeshGmsh.ui
|
||||
TaskPanelFemMeshGroup.ui
|
||||
TaskPanelFemMeshRegion.ui
|
||||
TaskPanelFemShellThickness.ui
|
||||
TaskPanelFemSolverCalculix.ui
|
||||
|
|
|
@ -42,6 +42,8 @@ FemResultObject::FemResultObject()
|
|||
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(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(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");
|
||||
|
@ -59,6 +61,8 @@ FemResultObject::FemResultObject()
|
|||
Stats.setStatus(App::Property::ReadOnly, true);
|
||||
DisplacementVectors.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);
|
||||
PrincipalMax.setStatus(App::Property::ReadOnly, true);
|
||||
PrincipalMed.setStatus(App::Property::ReadOnly, true);
|
||||
|
|
|
@ -49,8 +49,12 @@ public:
|
|||
App::PropertyFloatList Stats;
|
||||
/// Displacement vectors of analysis
|
||||
App::PropertyVectorList DisplacementVectors;
|
||||
/// Lengths of displacement vestors of analysis
|
||||
/// Lengths of displacement vectors of analysis
|
||||
App::PropertyFloatList DisplacementLengths;
|
||||
/// Stress vectors of analysis
|
||||
App::PropertyVectorList StressVectors;
|
||||
/// Strain vectors of analysis
|
||||
App::PropertyVectorList StrainVectors;
|
||||
/// Von Mises Stress values of analysis
|
||||
App::PropertyFloatList StressValues;
|
||||
/// 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);
|
||||
if(!res->StressValues.getValues().empty()) {
|
||||
const std::vector<double>& vec = res->StressValues.getValues();
|
||||
if (vec.size()>1) {
|
||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
data->SetNumberOfValues(vec.size());
|
||||
data->SetName("Von Mises stress");
|
||||
|
@ -768,10 +769,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
|||
data->SetValue(i, vec[i]);
|
||||
|
||||
grid->GetPointData()->AddArray(data);
|
||||
}
|
||||
}}
|
||||
|
||||
if(!res->StressValues.getValues().empty()) {
|
||||
if(!res->MaxShear.getValues().empty()) {
|
||||
const std::vector<double>& vec = res->MaxShear.getValues();
|
||||
if (vec.size()>1) {
|
||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
data->SetNumberOfValues(vec.size());
|
||||
data->SetName("Max shear stress (Tresca)");
|
||||
|
@ -780,10 +782,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
|||
data->SetValue(i, vec[i]);
|
||||
|
||||
grid->GetPointData()->AddArray(data);
|
||||
}
|
||||
}}
|
||||
|
||||
if(!res->StressValues.getValues().empty()) {
|
||||
if(!res->PrincipalMax.getValues().empty()) {
|
||||
const std::vector<double>& vec = res->PrincipalMax.getValues();
|
||||
if (vec.size()>1) {
|
||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
data->SetNumberOfValues(vec.size());
|
||||
data->SetName("Maximum Principal stress");
|
||||
|
@ -792,10 +795,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
|||
data->SetValue(i, vec[i]);
|
||||
|
||||
grid->GetPointData()->AddArray(data);
|
||||
}
|
||||
}}
|
||||
|
||||
if(!res->StressValues.getValues().empty()) {
|
||||
if(!res->PrincipalMax.getValues().empty()) {
|
||||
const std::vector<double>& vec = res->PrincipalMin.getValues();
|
||||
if (vec.size()>1) {
|
||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
data->SetNumberOfValues(vec.size());
|
||||
data->SetName("Minimum Principal stress");
|
||||
|
@ -804,10 +808,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
|||
data->SetValue(i, vec[i]);
|
||||
|
||||
grid->GetPointData()->AddArray(data);
|
||||
}
|
||||
}}
|
||||
|
||||
if(!res->StressValues.getValues().empty()) {
|
||||
if (!res->Temperature.getValues().empty()) {
|
||||
const std::vector<double>& vec = res->Temperature.getValues();
|
||||
if (vec.size()>1) {
|
||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
data->SetNumberOfValues(vec.size());
|
||||
data->SetName("Temperature");
|
||||
|
@ -816,10 +821,11 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
|||
data->SetValue(i, vec[i]);
|
||||
|
||||
grid->GetPointData()->AddArray(data);
|
||||
}
|
||||
}}
|
||||
|
||||
if(!res->StressValues.getValues().empty()) {
|
||||
if (!res->UserDefined.getValues().empty()) {
|
||||
const std::vector<double>& vec = res->UserDefined.getValues();
|
||||
if (vec.size()>1) {
|
||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
data->SetNumberOfValues(vec.size());
|
||||
data->SetName("User Defined Results");
|
||||
|
@ -828,11 +834,12 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
|||
data->SetValue(i, vec[i]);
|
||||
|
||||
grid->GetPointData()->AddArray(data);
|
||||
}
|
||||
}}
|
||||
|
||||
|
||||
if(!res->StressValues.getValues().empty()) {
|
||||
if(!res->DisplacementVectors.getValues().empty()) {
|
||||
const std::vector<Base::Vector3d>& vec = res->DisplacementVectors.getValues();
|
||||
if (vec.size()>1) {
|
||||
vtkSmartPointer<vtkDoubleArray> data = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
data->SetNumberOfComponents(3);
|
||||
data->SetName("Displacement");
|
||||
|
@ -843,7 +850,38 @@ void FemVTKTools::exportMechanicalResult(const App::DocumentObject* obj, vtkSmar
|
|||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -55,6 +55,13 @@ INSTALL(
|
|||
FemMesh2Mesh.py
|
||||
_CommandFEMMesh2Mesh.py
|
||||
|
||||
FemMeshGroup.py
|
||||
_FemMeshGroup.py
|
||||
_ViewProviderFemMeshGroup.py
|
||||
_CommandMeshGroup.py
|
||||
_TaskPanelFemMeshGroup.py
|
||||
TaskPanelFemMeshGroup.ui
|
||||
|
||||
FemMeshRegion.py
|
||||
_FemMeshRegion.py
|
||||
_ViewProviderFemMeshRegion.py
|
||||
|
|
|
@ -215,17 +215,39 @@ class FemGmshTools():
|
|||
print(' ' + self.gmsh_bin)
|
||||
|
||||
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:
|
||||
print(' Group meshing.')
|
||||
self.group_elements = FemMeshTools.get_analysis_group_elements(self.analysis, self.part_obj)
|
||||
print(' {}'.format(self.group_elements))
|
||||
new_group_elements = FemMeshTools.get_analysis_group_elements(self.analysis, 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:
|
||||
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_node_map = {} # { 'ElementString' : [element nodes] }
|
||||
if not self.mesh_obj.MeshRegionList:
|
||||
print (' No Mesh regions.')
|
||||
print (' No mesh regions.')
|
||||
else:
|
||||
print (' Mesh regions, we need to get the elements.')
|
||||
if self.part_obj.Shape.ShapeType == 'Compound':
|
||||
|
@ -279,7 +301,7 @@ class FemGmshTools():
|
|||
geo = open(self.temp_file_geo, "w")
|
||||
geo.write('Merge "' + self.temp_file_geometry + '";\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.')
|
||||
geo.write("// group data\n")
|
||||
# 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
|
||||
|
||||
|
||||
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):
|
||||
''' 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, ...], ...}
|
||||
'''
|
||||
aShape = aPart.Shape
|
||||
group_elements = {} # { name : [element, element, ... , element]}
|
||||
empty_references = []
|
||||
for m in aAnalysis.Member:
|
||||
if hasattr(m, "References"):
|
||||
# print(m.Name)
|
||||
key = m.Name
|
||||
if m.References:
|
||||
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 = []
|
||||
stype = None
|
||||
if m.References:
|
||||
for r in m.References:
|
||||
for r in obj.References:
|
||||
parent = r[0]
|
||||
childs = r[1]
|
||||
# print(parent)
|
||||
|
@ -1026,29 +1065,10 @@ def get_analysis_group_elements(aAnalysis, aPart):
|
|||
elements.append(found_element)
|
||||
else:
|
||||
FreeCAD.Console.PrintError('Problem: No element found for: ' + str(ref_shape) + '\n')
|
||||
print(' ' + m.Name)
|
||||
print(' ' + str(m.References))
|
||||
print(' ' + obj.Name)
|
||||
print(' ' + str(obj.References))
|
||||
print(' ' + r[0].Name)
|
||||
group_elements[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
|
||||
return (key, sorted(elements))
|
||||
|
||||
|
||||
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 not (self.fixed_constraints or self.displacement_constraints):
|
||||
message += "Static analysis: Neither constraint fixed nor constraint displacement defined.\n"
|
||||
if self.analysis_type == "static":
|
||||
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"
|
||||
# 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 self.analysis_type == "thermomech":
|
||||
if not self.initialtemperature_constraints:
|
||||
message += "Thermomechanical analysis: No initial temperature defined.\n"
|
||||
|
|
|
@ -71,6 +71,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
|||
<< "Fem_MeshNetgenFromShape"
|
||||
<< "Fem_MeshGmshFromShape"
|
||||
<< "Fem_MeshRegion"
|
||||
<< "Fem_MeshGroup"
|
||||
//<< "Fem_CreateNodesSet"
|
||||
<< "Separator"
|
||||
<< "Fem_Material"
|
||||
|
@ -143,6 +144,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
|||
<< "Fem_MeshNetgenFromShape"
|
||||
<< "Fem_MeshGmshFromShape"
|
||||
<< "Fem_MeshRegion"
|
||||
<< "Fem_MeshGroup"
|
||||
<< "Fem_CreateNodesSet"
|
||||
<< "Separator"
|
||||
<< "Fem_Material"
|
||||
|
|
|
@ -54,6 +54,7 @@ class FemWorkbench (Workbench):
|
|||
import _CommandFEMMesh2Mesh
|
||||
import _CommandMeshGmshFromShape
|
||||
import _CommandMeshNetgenFromShape
|
||||
import _CommandMeshGroup
|
||||
import _CommandMeshRegion
|
||||
import _CommandAnalysis
|
||||
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>
|
||||
<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">
|
||||
<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>
|
||||
</widget>
|
||||
</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.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.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"
|
||||
__author__ = "Juergen Riegel"
|
||||
__author__ = "Juergen Riegel, Michael Hindley"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
## @package TaskPanelShowResult
|
||||
|
@ -231,7 +231,15 @@ class _TaskPanelShowResult:
|
|||
x = np.array(dispvectors[:, 0])
|
||||
y = np.array(dispvectors[:, 1])
|
||||
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
|
||||
UserDefinedFormula = eval(userdefined_eq).tolist()
|
||||
self.result_object.UserDefined = UserDefinedFormula
|
||||
|
|
|
@ -112,7 +112,7 @@ class _ViewProviderFemMeshGmsh:
|
|||
return None
|
||||
|
||||
def claimChildren(self):
|
||||
return self.Object.MeshRegionList
|
||||
return (self.Object.MeshRegionList + self.Object.MeshGroupList)
|
||||
|
||||
def onDelete(self, feature, subelements):
|
||||
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_quad8 = {}
|
||||
elements_seg2 = {}
|
||||
elements_seg3 = {}
|
||||
results = []
|
||||
mode_results = {}
|
||||
mode_disp = {}
|
||||
mode_stress = {}
|
||||
mode_stressv = {}
|
||||
mode_strain = {}
|
||||
mode_temp = {}
|
||||
|
||||
mode_disp_found = False
|
||||
nodes_found = False
|
||||
mode_stress_found = False
|
||||
mode_strain_found = False
|
||||
mode_temp_found = False
|
||||
mode_time_found = False
|
||||
elements_found = False
|
||||
|
@ -250,6 +254,14 @@ def readResult(frd_input):
|
|||
nd1 = int(line[3:13])
|
||||
nd2 = int(line[13:23])
|
||||
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
|
||||
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)
|
||||
if line[5:11] == "STRESS":
|
||||
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"):
|
||||
elem = int(line[4:13])
|
||||
stress_1 = float(line[13:25])
|
||||
|
@ -276,6 +288,19 @@ def readResult(frd_input):
|
|||
stress_5 = float(line[61:73])
|
||||
stress_6 = float(line[73:85])
|
||||
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
|
||||
if line[4:10] == "1PSTEP":
|
||||
mode_time_found = True
|
||||
|
@ -309,6 +334,8 @@ def readResult(frd_input):
|
|||
mode_results['number'] = eigenmode
|
||||
mode_results['disp'] = mode_disp
|
||||
mode_results['stress'] = mode_stress
|
||||
mode_results['stressv'] = mode_stressv
|
||||
mode_results['strainv'] = mode_strain
|
||||
mode_results['temp'] = mode_temp
|
||||
mode_results['time'] = timestep
|
||||
results.append(mode_results)
|
||||
|
@ -322,6 +349,8 @@ def readResult(frd_input):
|
|||
mode_results['number'] = eigenmode
|
||||
mode_results['disp'] = mode_disp
|
||||
mode_results['stress'] = mode_stress
|
||||
mode_results['stressv'] = mode_stressv
|
||||
mode_results['strainv'] = mode_strain
|
||||
mode_results['time'] = 0 # Dont return time if static
|
||||
results.append(mode_results)
|
||||
mode_disp = {}
|
||||
|
@ -336,7 +365,7 @@ def readResult(frd_input):
|
|||
return {'Nodes': nodes,
|
||||
'Hexa8Elem': elements_hexa8, 'Penta6Elem': elements_penta6, 'Tetra4Elem': elements_tetra4, 'Tetra10Elem': elements_tetra10,
|
||||
'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}
|
||||
|
||||
|
||||
|
@ -421,6 +450,8 @@ def importFrd(filename, analysis=None, result_name_prefix=None):
|
|||
break
|
||||
|
||||
disp = result_set['disp']
|
||||
stressv = result_set['stressv']
|
||||
strainv = result_set['strainv']
|
||||
no_of_values = len(disp)
|
||||
displacement = []
|
||||
for k, v in disp.iteritems():
|
||||
|
@ -438,6 +469,8 @@ def importFrd(filename, analysis=None, result_name_prefix=None):
|
|||
|
||||
if len(disp) > 0:
|
||||
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()
|
||||
if(mesh_object):
|
||||
results.Mesh = mesh_object
|
||||
|
|
|
@ -30,10 +30,10 @@ the module
|
|||
'''
|
||||
|
||||
try:
|
||||
from PySide import QtGui
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
def translate(context, text):
|
||||
"convenience function for Qt translator"
|
||||
from PySide import QtGui
|
||||
return QtGui.QApplication.translate(context, text, None, _encoding)
|
||||
except AttributeError:
|
||||
def translate(context, text):
|
||||
|
|
|
@ -186,7 +186,7 @@ Intersection of this and a given list of topo shapes.
|
|||
|
||||
Supports:
|
||||
- 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
|
||||
|
||||
OCC 6.9.0 or later is required.</UserDocu>
|
||||
|
@ -203,7 +203,7 @@ Section of this and a given list of topo shapes.
|
|||
|
||||
Supports:
|
||||
- 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
|
||||
|
||||
OCC 6.9.0 or later is required.</UserDocu>
|
||||
|
|
|
@ -99,7 +99,7 @@ public:
|
|||
~TaskCheckGeometryResults();
|
||||
QString getShapeContentString();
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void currentRowChanged (const QModelIndex ¤t, const QModelIndex &previous);
|
||||
|
||||
private:
|
||||
|
|
|
@ -198,7 +198,7 @@ protected:
|
|||
QPixmap *stepActive;
|
||||
QPixmap *stepDone;
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void selectionSlot(bool checked);
|
||||
void buildPixmaps();
|
||||
|
||||
|
@ -229,7 +229,7 @@ class DimensionControl : public QWidget
|
|||
public:
|
||||
explicit DimensionControl(QWidget* parent);
|
||||
QPushButton *resetButton;
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void toggle3dSlot(bool);
|
||||
void toggleDeltaSlot(bool);
|
||||
void clearAllSlot(bool);
|
||||
|
@ -250,7 +250,7 @@ public:
|
|||
protected:
|
||||
virtual void onSelectionChanged(const Gui::SelectionChanges& msg);
|
||||
|
||||
protected slots:
|
||||
protected Q_SLOTS:
|
||||
void selection1Slot(bool checked);
|
||||
void selection2Slot(bool checked);
|
||||
void resetDialogSlot(bool);
|
||||
|
@ -326,7 +326,7 @@ public:
|
|||
protected:
|
||||
virtual void onSelectionChanged(const Gui::SelectionChanges& msg);
|
||||
|
||||
protected slots:
|
||||
protected Q_SLOTS:
|
||||
void selection1Slot(bool checked);
|
||||
void selection2Slot(bool checked);
|
||||
void resetDialogSlot(bool);
|
||||
|
|
|
@ -121,12 +121,12 @@ int ToolPy::PyInit(PyObject* args, PyObject* kwd)
|
|||
else
|
||||
getToolPtr()->Material = Tool::MATUNDEFINED;
|
||||
|
||||
getToolPtr()->Diameter = PyFloat_AsDouble(dia);
|
||||
getToolPtr()->LengthOffset = PyFloat_AsDouble(len);
|
||||
getToolPtr()->FlatRadius = PyFloat_AsDouble(fla);
|
||||
getToolPtr()->CornerRadius = PyFloat_AsDouble(cor);
|
||||
getToolPtr()->CuttingEdgeAngle = PyFloat_AsDouble(ang);
|
||||
getToolPtr()->CuttingEdgeHeight = PyFloat_AsDouble(hei);
|
||||
getToolPtr()->Diameter = dia ? PyFloat_AsDouble(dia) : 0.0;
|
||||
getToolPtr()->LengthOffset = len ? PyFloat_AsDouble(len) : 0.0;
|
||||
getToolPtr()->FlatRadius = fla ? PyFloat_AsDouble(fla) : 0.0;
|
||||
getToolPtr()->CornerRadius = cor ? PyFloat_AsDouble(cor) : 0.0;
|
||||
getToolPtr()->CuttingEdgeAngle = ang ? PyFloat_AsDouble(ang) : 0.0;
|
||||
getToolPtr()->CuttingEdgeHeight = hei ? PyFloat_AsDouble(hei) : 0.0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ SET(PathScripts_SRCS
|
|||
PathScripts/PathSimpleCopy.py
|
||||
PathScripts/PathStock.py
|
||||
PathScripts/PathStop.py
|
||||
PathScripts/PathHelix.py
|
||||
PathScripts/PathSurface.py
|
||||
PathScripts/PathToolLenOffset.py
|
||||
PathScripts/PathToolLibraryManager.py
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<file>icons/Path-FaceProfile.svg</file>
|
||||
<file>icons/Path-Face.svg</file>
|
||||
<file>icons/Path-Heights.svg</file>
|
||||
<file>icons/Path-Helix.svg</file>
|
||||
<file>icons/Path-Hop.svg</file>
|
||||
<file>icons/Path-Inspect.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 PathInspect
|
||||
from PathScripts import PathSimpleCopy
|
||||
from PathScripts import PathHelix
|
||||
from PathScripts import PathEngrave
|
||||
from PathScripts import PathSurface
|
||||
from PathScripts import PathSanity
|
||||
|
@ -80,7 +81,7 @@ class PathWorkbench (Workbench):
|
|||
projcmdlist = ["Path_Job", "Path_Post", "Path_Inspect", "Path_Sanity"]
|
||||
toolcmdlist = ["Path_ToolLibraryEdit", "Path_LoadTool"]
|
||||
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"]
|
||||
modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", "Path_SimpleCopy" ]
|
||||
dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_HoldingTags"]
|
||||
|
|
|
@ -275,7 +275,7 @@ class Chord (object):
|
|||
return dir == 'Back' or dir == side
|
||||
|
||||
def connectsTo(self, chord):
|
||||
return PathGeom.isRoughly(self.End, chord.Start)
|
||||
return PathGeom.pointsCoincide(self.End, chord.Start)
|
||||
|
||||
class Bone:
|
||||
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
|
||||
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Tools2D.h>
|
||||
#include <App/Application.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Document.h>
|
||||
|
@ -3252,10 +3253,29 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
|||
Base::Vector3d p1b = lineSeg1->getEndPoint();
|
||||
Base::Vector3d p2a = lineSeg2->getStartPoint();
|
||||
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;
|
||||
for (int i=0; i <= 1; i++) {
|
||||
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) {
|
||||
length = tmp;
|
||||
PosId1 = i ? Sketcher::start : Sketcher::end;
|
||||
|
@ -3263,6 +3283,7 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Base::Vector3d dir1 = ((PosId1 == Sketcher::start) ? 1. : -1.) *
|
||||
(lineSeg1->getEndPoint()-lineSeg1->getStartPoint());
|
||||
|
@ -3280,8 +3301,8 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
|||
}
|
||||
}
|
||||
|
||||
double ActAngle = atan2(-dir1.y*dir2.x+dir1.x*dir2.y,
|
||||
dir1.x*dir2.x+dir1.y*dir2.y);
|
||||
double ActAngle = atan2(dir1.x*dir2.y-dir1.y*dir2.x,
|
||||
dir1.y*dir2.y+dir1.x*dir2.x);
|
||||
if (ActAngle < 0) {
|
||||
ActAngle *= -1;
|
||||
std::swap(GeoId1,GeoId2);
|
||||
|
|
|
@ -181,7 +181,7 @@ signals:
|
|||
void clicked();
|
||||
void selected();
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void setColor(const QColor &color, const QString &text = QString());
|
||||
|
||||
protected:
|
||||
|
@ -224,10 +224,10 @@ signals:
|
|||
void selected(const QColor &);
|
||||
void hid();
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void getColorFromDialog();
|
||||
|
||||
protected slots:
|
||||
protected Q_SLOTS:
|
||||
void updateSelected();
|
||||
|
||||
protected:
|
||||
|
@ -434,7 +434,7 @@ void QtColorPicker::setStandardColors()
|
|||
void QtColorPicker::setCurrentColor(const QColor &color)
|
||||
{
|
||||
if (color.isValid() && col == color) {
|
||||
emit colorSet(color);
|
||||
Q_EMIT colorSet(color);
|
||||
return;
|
||||
}
|
||||
if (col == color || !color.isValid())
|
||||
|
@ -457,8 +457,8 @@ void QtColorPicker::setCurrentColor(const QColor &color)
|
|||
repaint();
|
||||
|
||||
item->setSelected(true);
|
||||
emit colorChanged(color);
|
||||
emit colorSet(color);
|
||||
Q_EMIT colorChanged(color);
|
||||
Q_EMIT colorSet(color);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -679,7 +679,7 @@ void ColorPickerPopup::updateSelected()
|
|||
if (sender() && sender()->inherits("ColorPickerItem")) {
|
||||
ColorPickerItem *item = (ColorPickerItem *)sender();
|
||||
lastSel = item->color();
|
||||
emit selected(item->color());
|
||||
Q_EMIT selected(item->color());
|
||||
}
|
||||
|
||||
hide();
|
||||
|
@ -764,7 +764,7 @@ void ColorPickerPopup::keyPressEvent(QKeyEvent *e)
|
|||
}
|
||||
|
||||
lastSel = wi->color();
|
||||
emit selected(wi->color());
|
||||
Q_EMIT selected(wi->color());
|
||||
hide();
|
||||
} else if (w && w->inherits("QPushButton")) {
|
||||
ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
|
||||
|
@ -784,7 +784,7 @@ void ColorPickerPopup::keyPressEvent(QKeyEvent *e)
|
|||
}
|
||||
|
||||
lastSel = wi->color();
|
||||
emit selected(wi->color());
|
||||
Q_EMIT selected(wi->color());
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
@ -811,7 +811,7 @@ void ColorPickerPopup::hideEvent(QHideEvent *e)
|
|||
|
||||
setFocus();
|
||||
|
||||
emit hid();
|
||||
Q_EMIT hid();
|
||||
QFrame::hideEvent(e);
|
||||
}
|
||||
|
||||
|
@ -906,7 +906,7 @@ void ColorPickerPopup::getColorFromDialog()
|
|||
//QColor col = QColor::fromRgba(rgb);
|
||||
insertColor(col, tr("Custom"), -1);
|
||||
lastSel = col;
|
||||
emit selected(col);
|
||||
Q_EMIT selected(col);
|
||||
}
|
||||
|
||||
void ColorPickerPopup::setLastSel(const QColor & col) { lastSel = col; }
|
||||
|
@ -994,7 +994,7 @@ void ColorPickerItem::mouseMoveEvent(QMouseEvent *)
|
|||
void ColorPickerItem::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
sel = true;
|
||||
emit selected();
|
||||
Q_EMIT selected();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1062,7 +1062,7 @@ void ColorPickerButton::mouseReleaseEvent(QMouseEvent *)
|
|||
{
|
||||
setFrameShadow(Raised);
|
||||
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) {
|
||||
setFrameShadow(Raised);
|
||||
repaint();
|
||||
emit clicked();
|
||||
Q_EMIT clicked();
|
||||
} else {
|
||||
QFrame::keyReleaseEvent(e);
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ void FileChooser::chooseFile()
|
|||
|
||||
if (!fn.isEmpty()) {
|
||||
lineEdit->setText(fn);
|
||||
emit fileNameSelected(fn);
|
||||
Q_EMIT fileNameSelected(fn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1032,7 +1032,7 @@ void ColorButton::onChooseColor()
|
|||
if ( c.isValid() )
|
||||
{
|
||||
setColor( c );
|
||||
emit changed();
|
||||
Q_EMIT changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ void Wizard::setCurrentIndex(int index)
|
|||
textLabel->setText(stackWidget->currentWidget()->windowTitle());
|
||||
_backButton->setEnabled(index > 0);
|
||||
_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);
|
||||
textLabel->setText(newTitle);
|
||||
emit pageTitleChanged(newTitle);
|
||||
Q_EMIT pageTitleChanged(newTitle);
|
||||
}
|
||||
|
||||
WizardExtension::WizardExtension(Wizard *widget, QObject *parent)
|
||||
|
|
Loading…
Reference in New Issue
Block a user