Merge remote-tracking branch 'origin/master' into step

This commit is contained in:
Jean-Marie Verdun 2017-01-08 21:55:46 +01:00
commit 358238f745
48 changed files with 2715 additions and 598 deletions

View File

@ -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

View File

@ -69,7 +69,7 @@ public:
void pause();
void resume();
private slots:
private Q_SLOTS:
void readClient();
void discardClient();

View File

@ -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();
}
}

View File

@ -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);

View File

@ -48,7 +48,7 @@ public:
SensorManager(void);
~SensorManager();
public slots:
public Q_SLOTS:
void idleTimeout(void);
void delayTimeout(void);
void timerQueueTimeout(void);

View File

@ -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();
}
}
}

View File

@ -9,193 +9,193 @@
#include "iistaskpanelscheme.h"
iisIconLabel::iisIconLabel(const QIcon &icon, const QString &title, QWidget *parent)
: QWidget(parent),
myPixmap(icon),
myText(title),
mySchemePointer(0),
m_over(false),
m_pressed(false),
m_changeCursorOver(true),
m_underlineOver(true)
: QWidget(parent),
myPixmap(icon),
myText(title),
mySchemePointer(0),
m_over(false),
m_pressed(false),
m_changeCursorOver(true),
m_underlineOver(true)
{
setFocusPolicy(Qt::StrongFocus);
setCursor(Qt::PointingHandCursor);
setFocusPolicy(Qt::StrongFocus);
setCursor(Qt::PointingHandCursor);
myFont.setWeight(0);
myPen.setStyle(Qt::NoPen);
myFont.setWeight(0);
myPen.setStyle(Qt::NoPen);
myColor = myColorOver = myColorDisabled = QColor();
myColor = myColorOver = myColorDisabled = QColor();
}
iisIconLabel::~iisIconLabel()
{
//if (m_changeCursorOver)
// QApplication::restoreOverrideCursor();
//if (m_changeCursorOver)
// QApplication::restoreOverrideCursor();
}
void iisIconLabel::setSchemePointer(iisIconLabelScheme **pointer)
{
mySchemePointer = pointer;
update();
mySchemePointer = pointer;
update();
}
void iisIconLabel::setColors(const QColor &color, const QColor &colorOver, const QColor &colorOff)
{
myColor = color;
myColorOver = colorOver;
myColorDisabled = colorOff;
update();
myColor = color;
myColorOver = colorOver;
myColorDisabled = colorOff;
update();
}
void iisIconLabel::setFont(const QFont &font)
{
myFont = font;
update();
myFont = font;
update();
}
void iisIconLabel::setFocusPen(const QPen &pen)
{
myPen = pen;
update();
myPen = pen;
update();
}
QSize iisIconLabel::sizeHint() const
{
return minimumSize();
return minimumSize();
}
QSize iisIconLabel::minimumSizeHint() const
{
int s = (mySchemePointer && *mySchemePointer) ? (*mySchemePointer)->iconSize : 16;
QPixmap px = myPixmap.pixmap(s,s,
isEnabled() ? QIcon::Normal : QIcon::Disabled);
int s = (mySchemePointer && *mySchemePointer) ? (*mySchemePointer)->iconSize : 16;
QPixmap px = myPixmap.pixmap(s,s,
isEnabled() ? QIcon::Normal : QIcon::Disabled);
int h = 4+px.height();
int w = 8 + px.width();
if (!myText.isEmpty()) {
QFontMetrics fm(myFont);
w += fm.width(myText);
h = qMax(h, 4+fm.height());
}
int h = 4+px.height();
int w = 8 + px.width();
if (!myText.isEmpty()) {
QFontMetrics fm(myFont);
w += fm.width(myText);
h = qMax(h, 4+fm.height());
}
return QSize(w+2,h+2);
return QSize(w+2,h+2);
}
void iisIconLabel::paintEvent ( QPaintEvent * event )
void iisIconLabel::paintEvent ( QPaintEvent * event )
{
Q_UNUSED(event);
QPainter p(this);
Q_UNUSED(event);
QPainter p(this);
QRect textRect(rect().adjusted(0,0,-1,0));
QRect textRect(rect().adjusted(0,0,-1,0));
int x = 2;
int x = 2;
if (!myPixmap.isNull()) {
int s = (mySchemePointer && *mySchemePointer) ? (*mySchemePointer)->iconSize : 16;
QPixmap px = myPixmap.pixmap(s,s,
isEnabled() ? QIcon::Normal : QIcon::Disabled);
p.drawPixmap(x,0,px);
x += px.width() + 4;
}
if (!myPixmap.isNull()) {
int s = (mySchemePointer && *mySchemePointer) ? (*mySchemePointer)->iconSize : 16;
QPixmap px = myPixmap.pixmap(s,s,
isEnabled() ? QIcon::Normal : QIcon::Disabled);
p.drawPixmap(x,0,px);
x += px.width() + 4;
}
if (!myText.isEmpty()) {
QColor text = myColor, textOver = myColorOver, textOff = myColorDisabled;
QFont fnt = myFont;
QPen focusPen = myPen;
bool underline = m_underlineOver/*, cursover = m_changeCursorOver*/;
if (mySchemePointer && *mySchemePointer) {
if (!text.isValid()) text = (*mySchemePointer)->text;
if (!textOver.isValid()) textOver = (*mySchemePointer)->textOver;
if (!textOff.isValid()) textOff = (*mySchemePointer)->textOff;
if (!fnt.weight()) fnt = (*mySchemePointer)->font;
if (focusPen.style() == Qt::NoPen) focusPen = (*mySchemePointer)->focusPen;
underline = (*mySchemePointer)->underlineOver;
//cursover = (*mySchemePointer)->cursorOver;
}
if (!myText.isEmpty()) {
QColor text = myColor, textOver = myColorOver, textOff = myColorDisabled;
QFont fnt = myFont;
QPen focusPen = myPen;
bool underline = m_underlineOver/*, cursover = m_changeCursorOver*/;
if (mySchemePointer && *mySchemePointer) {
if (!text.isValid()) text = (*mySchemePointer)->text;
if (!textOver.isValid()) textOver = (*mySchemePointer)->textOver;
if (!textOff.isValid()) textOff = (*mySchemePointer)->textOff;
if (!fnt.weight()) fnt = (*mySchemePointer)->font;
if (focusPen.style() == Qt::NoPen) focusPen = (*mySchemePointer)->focusPen;
underline = (*mySchemePointer)->underlineOver;
//cursover = (*mySchemePointer)->cursorOver;
}
p.setPen(isEnabled() ? m_over ? textOver : text : textOff);
p.setPen(isEnabled() ? m_over ? textOver : text : textOff);
if (isEnabled() && underline && m_over)
fnt.setUnderline(true);
p.setFont(fnt);
if (isEnabled() && underline && m_over)
fnt.setUnderline(true);
p.setFont(fnt);
textRect.setLeft(x);
QRect boundingRect;
textRect.setLeft(x);
QRect boundingRect;
QFontMetrics fm(fnt);
QFontMetrics fm(fnt);
#if QT_VERSION >= 0x040203
QString txt(fm.elidedText(myText, Qt::ElideRight, textRect.width()));
QString txt(fm.elidedText(myText, Qt::ElideRight, textRect.width()));
#else
QString txt = myText;
QString txt = myText;
#endif
p.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, txt, &boundingRect);
p.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, txt, &boundingRect);
if (hasFocus()) {
p.setPen(focusPen);
p.drawRect(boundingRect.adjusted(-2,-1,0,0));
}
}
if (hasFocus()) {
p.setPen(focusPen);
p.drawRect(boundingRect.adjusted(-2,-1,0,0));
}
}
}
void iisIconLabel::enterEvent ( QEvent * /*event*/ )
{
m_over = true;
m_over = true;
//if (m_changeCursorOver)
// QApplication::setOverrideCursor(Qt::PointingHandCursor);
//if (m_changeCursorOver)
// QApplication::setOverrideCursor(Qt::PointingHandCursor);
update();
update();
}
void iisIconLabel::leaveEvent ( QEvent * /*event*/ )
{
m_over = false;
update();
m_over = false;
update();
//if (m_changeCursorOver)
// QApplication::restoreOverrideCursor();
//if (m_changeCursorOver)
// QApplication::restoreOverrideCursor();
}
void iisIconLabel::mousePressEvent ( QMouseEvent * event )
{
if (event->button() == Qt::LeftButton) {
m_pressed = true;
emit pressed();
} else
if (event->button() == Qt::RightButton)
emit contextMenu();
if (event->button() == Qt::LeftButton) {
m_pressed = true;
Q_EMIT pressed();
} else
if (event->button() == Qt::RightButton)
Q_EMIT contextMenu();
update();
update();
}
void iisIconLabel::mouseReleaseEvent ( QMouseEvent * event )
{
if (event->button() == Qt::LeftButton) {
m_pressed = false;
emit released();
if (event->button() == Qt::LeftButton) {
m_pressed = false;
Q_EMIT released();
if (rect().contains( event->pos() )) {
emit clicked();
emit activated();
}
}
if (rect().contains( event->pos() )) {
Q_EMIT clicked();
Q_EMIT activated();
}
}
update();
update();
}
void iisIconLabel::keyPressEvent ( QKeyEvent * event )
{
switch (event->key()) {
case Qt::Key_Space:
case Qt::Key_Return:
emit activated();
break;
switch (event->key()) {
case Qt::Key_Space:
case Qt::Key_Return:
Q_EMIT activated();
break;
default:;
}
default:;
}
QWidget::keyPressEvent(event);
QWidget::keyPressEvent(event);
}

View File

@ -16,38 +16,38 @@
#include "iisiconlabel.h"
iisTaskHeader::iisTaskHeader(const QIcon &icon, const QString &title, bool expandable, QWidget *parent)
: QFrame(parent),
myExpandable(expandable),
m_over(false),
m_buttonOver(false),
m_fold(true),
m_opacity(0.1),
myButton(0)
: QFrame(parent),
myExpandable(expandable),
m_over(false),
m_buttonOver(false),
m_fold(true),
m_opacity(0.1),
myButton(0)
{
myTitle = new iisIconLabel(icon, title, this);
myTitle->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
myTitle = new iisIconLabel(icon, title, this);
myTitle->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
connect(myTitle, SIGNAL(activated()), this, SLOT(fold()));
connect(myTitle, SIGNAL(activated()), this, SLOT(fold()));
QHBoxLayout *hbl = new QHBoxLayout();
hbl->setMargin(2);
setLayout(hbl);
QHBoxLayout *hbl = new QHBoxLayout();
hbl->setMargin(2);
setLayout(hbl);
hbl->addWidget(myTitle);
hbl->addWidget(myTitle);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
setScheme(iisTaskPanelScheme::defaultScheme());
myTitle->setSchemePointer(&myLabelScheme);
setScheme(iisTaskPanelScheme::defaultScheme());
myTitle->setSchemePointer(&myLabelScheme);
if (myExpandable) {
myButton = new QLabel(this);
hbl->addWidget(myButton);
myButton->installEventFilter(this);
myButton->setFixedWidth(myScheme->headerButtonSize.width());
changeIcons();
}
if (myExpandable) {
myButton = new QLabel(this);
hbl->addWidget(myButton);
myButton->installEventFilter(this);
myButton->setFixedWidth(myScheme->headerButtonSize.width());
changeIcons();
}
}
iisTaskHeader::~iisTaskHeader()
@ -57,145 +57,145 @@ iisTaskHeader::~iisTaskHeader()
bool iisTaskHeader::eventFilter(QObject *obj, QEvent *event)
{
switch (event->type()) {
case QEvent::MouseButtonPress:
fold();
return true;
switch (event->type()) {
case QEvent::MouseButtonPress:
fold();
return true;
case QEvent::Enter:
m_buttonOver = true;
changeIcons();
return true;
case QEvent::Enter:
m_buttonOver = true;
changeIcons();
return true;
case QEvent::Leave:
m_buttonOver = false;
changeIcons();
return true;
case QEvent::Leave:
m_buttonOver = false;
changeIcons();
return true;
default:;
}
default:;
}
return QFrame::eventFilter(obj, event);
return QFrame::eventFilter(obj, event);
}
void iisTaskHeader::setScheme(iisTaskPanelScheme *scheme)
{
if (scheme) {
myScheme = scheme;
myLabelScheme = &(scheme->headerLabelScheme);
if (scheme) {
myScheme = scheme;
myLabelScheme = &(scheme->headerLabelScheme);
if (myExpandable) {
setCursor(myLabelScheme->cursorOver ? Qt::PointingHandCursor : cursor());
changeIcons();
}
if (myExpandable) {
setCursor(myLabelScheme->cursorOver ? Qt::PointingHandCursor : cursor());
changeIcons();
}
setFixedHeight(scheme->headerSize);
setFixedHeight(scheme->headerSize);
update();
}
update();
}
}
void iisTaskHeader::paintEvent ( QPaintEvent * event )
void iisTaskHeader::paintEvent ( QPaintEvent * event )
{
Q_UNUSED(event);
QPainter p(this);
Q_UNUSED(event);
QPainter p(this);
#if QT_VERSION >= 0x040203
if (myScheme->headerAnimation)
p.setOpacity(m_opacity+0.7);
if (myScheme->headerAnimation)
p.setOpacity(m_opacity+0.7);
#endif
p.setPen(myScheme->headerBorder);
p.setBrush(myScheme->headerBackground);
if (myScheme->headerBorder.style() == Qt::NoPen)
p.drawRect(rect());
else
p.drawRect(rect().adjusted(0,0,-1,-1));
p.setPen(myScheme->headerBorder);
p.setBrush(myScheme->headerBackground);
if (myScheme->headerBorder.style() == Qt::NoPen)
p.drawRect(rect());
else
p.drawRect(rect().adjusted(0,0,-1,-1));
}
void iisTaskHeader::animate()
{
if (!myScheme->headerAnimation)
return;
if (!myScheme->headerAnimation)
return;
if (!isEnabled()) {
m_opacity = 0.1;
update();
return;
}
if (!isEnabled()) {
m_opacity = 0.1;
update();
return;
}
if (m_over) {
if (m_opacity >= 0.3) {
m_opacity = 0.3;
return;
}
m_opacity += 0.05;
} else {
if (m_opacity <= 0.1) {
m_opacity = 0.1;
return;
}
m_opacity = qMax(0.1, m_opacity-0.05);
}
if (m_over) {
if (m_opacity >= 0.3) {
m_opacity = 0.3;
return;
}
m_opacity += 0.05;
} else {
if (m_opacity <= 0.1) {
m_opacity = 0.1;
return;
}
m_opacity = qMax(0.1, m_opacity-0.05);
}
QTimer::singleShot(100, this, SLOT(animate()));
update();
QTimer::singleShot(100, this, SLOT(animate()));
update();
}
void iisTaskHeader::enterEvent ( QEvent * /*event*/ )
{
m_over = true;
m_over = true;
if (isEnabled())
QTimer::singleShot(100, this, SLOT(animate()));
if (isEnabled())
QTimer::singleShot(100, this, SLOT(animate()));
update();
update();
}
void iisTaskHeader::leaveEvent ( QEvent * /*event*/ )
{
m_over = false;
if (isEnabled())
QTimer::singleShot(100, this, SLOT(animate()));
m_over = false;
update();
if (isEnabled())
QTimer::singleShot(100, this, SLOT(animate()));
update();
}
void iisTaskHeader::fold()
{
if (myExpandable) {
emit activated();
if (myExpandable) {
Q_EMIT activated();
m_fold = !m_fold;
changeIcons();
}
m_fold = !m_fold;
changeIcons();
}
}
void iisTaskHeader::changeIcons()
{
if (!myButton)
return;
if (!myButton)
return;
if (m_buttonOver)
{
if (m_fold)
myButton->setPixmap(myScheme->headerButtonFoldOver.pixmap(myScheme->headerButtonSize));
else
myButton->setPixmap(myScheme->headerButtonUnfoldOver.pixmap(myScheme->headerButtonSize));
} else
{
if (m_fold)
myButton->setPixmap(myScheme->headerButtonFold.pixmap(myScheme->headerButtonSize));
else
myButton->setPixmap(myScheme->headerButtonUnfold.pixmap(myScheme->headerButtonSize));
}
if (m_buttonOver)
{
if (m_fold)
myButton->setPixmap(myScheme->headerButtonFoldOver.pixmap(myScheme->headerButtonSize));
else
myButton->setPixmap(myScheme->headerButtonUnfoldOver.pixmap(myScheme->headerButtonSize));
} else
{
if (m_fold)
myButton->setPixmap(myScheme->headerButtonFold.pixmap(myScheme->headerButtonSize));
else
myButton->setPixmap(myScheme->headerButtonUnfold.pixmap(myScheme->headerButtonSize));
}
}
void iisTaskHeader::mouseReleaseEvent ( QMouseEvent * event )
{
if (event->button() == Qt::LeftButton) {
emit activated();
}
if (event->button() == Qt::LeftButton) {
Q_EMIT activated();
}
}

View File

@ -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>

View File

@ -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 &quot;Arial:Bold&quot;</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 &quot;Arial:Bold&quot;</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 &quot;Arial:Bold&quot;</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 &quot;Arial:Bold&quot;</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/>

View File

@ -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,\

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -108,7 +108,7 @@ template<class TWriter> void writeVTKFile(const char* filename, vtkSmartPointer<
writer->SetInputData(dataset);
writer->Write();
}
void FemVTKTools::importVTKMesh(vtkSmartPointer<vtkDataSet> dataset, FemMesh* mesh)
{
const vtkIdType nPoints = dataset->GetNumberOfPoints();
@ -184,7 +184,7 @@ FemMesh* FemVTKTools::readVTKMesh(const char* filename, FemMesh* mesh)
Base::TimeInfo Start;
Base::Console().Log("Start: read FemMesh from VTK unstructuredGrid ======================\n");
Base::FileInfo f(filename);
if(f.hasExtension("vtu"))
{
vtkSmartPointer<vtkDataSet> dataset = readVTKFile<vtkXMLUnstructuredGridReader>(filename);
@ -236,7 +236,7 @@ void exportFemMeshFaces(vtkSmartPointer<vtkUnstructuredGrid> grid, const SMDS_Fa
quad->GetPointIds()->SetId(1, aFace->GetNode(1)->GetID()-1);
quad->GetPointIds()->SetId(2, aFace->GetNode(2)->GetID()-1);
quad->GetPointIds()->SetId(3, aFace->GetNode(3)->GetID()-1);
quadArray->InsertNextCell(quad);
}
//quadratic triangle
@ -263,7 +263,7 @@ void exportFemMeshFaces(vtkSmartPointer<vtkUnstructuredGrid> grid, const SMDS_Fa
quad->GetPointIds()->SetId(5, aFace->GetNode(5)->GetID()-1);
quad->GetPointIds()->SetId(6, aFace->GetNode(6)->GetID()-1);
quad->GetPointIds()->SetId(7, aFace->GetNode(7)->GetID()-1);
quadQuadArray->InsertNextCell(quad);
}
}
@ -275,7 +275,7 @@ void exportFemMeshFaces(vtkSmartPointer<vtkUnstructuredGrid> grid, const SMDS_Fa
if(quadTriangleArray->GetNumberOfCells()>0)
grid->SetCells(VTK_QUADRATIC_TRIANGLE, quadTriangleArray);
if(quadQuadArray->GetNumberOfCells()>0)
grid->SetCells(VTK_QUADRATIC_QUAD, quadQuadArray);
@ -291,7 +291,7 @@ void exportFemMeshCells(vtkSmartPointer<vtkUnstructuredGrid> grid, const SMDS_Vo
// quadratic elemnts with 13 and 15 nodes are not added yet
vtkSmartPointer<vtkCellArray> quadTetraArray = vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkCellArray> quadHexaArray = vtkSmartPointer<vtkCellArray>::New();
for (;aVolIter->more();)
{
const SMDS_MeshVolume* aVol = aVolIter->next();
@ -314,7 +314,7 @@ void exportFemMeshCells(vtkSmartPointer<vtkUnstructuredGrid> grid, const SMDS_Vo
cell->GetPointIds()->SetId(2, aVol->GetNode(2)->GetID()-1);
cell->GetPointIds()->SetId(3, aVol->GetNode(3)->GetID()-1);
cell->GetPointIds()->SetId(4, aVol->GetNode(4)->GetID()-1);
pyramidArray->InsertNextCell(cell);
}
if(aVol->NbNodes() == 6) {
@ -325,7 +325,7 @@ void exportFemMeshCells(vtkSmartPointer<vtkUnstructuredGrid> grid, const SMDS_Vo
cell->GetPointIds()->SetId(3, aVol->GetNode(3)->GetID()-1);
cell->GetPointIds()->SetId(4, aVol->GetNode(4)->GetID()-1);
cell->GetPointIds()->SetId(5, aVol->GetNode(5)->GetID()-1);
wedgeArray->InsertNextCell(cell);
}
if(aVol->NbNodes() == 8) {
@ -338,7 +338,7 @@ void exportFemMeshCells(vtkSmartPointer<vtkUnstructuredGrid> grid, const SMDS_Vo
cell->GetPointIds()->SetId(5, aVol->GetNode(5)->GetID()-1);
cell->GetPointIds()->SetId(6, aVol->GetNode(6)->GetID()-1);
cell->GetPointIds()->SetId(7, aVol->GetNode(7)->GetID()-1);
hexaArray->InsertNextCell(cell);
}
//quadratic tetrahedra
@ -371,10 +371,10 @@ void exportFemMeshCells(vtkSmartPointer<vtkUnstructuredGrid> grid, const SMDS_Vo
if(hexaArray->GetNumberOfCells()>0)
grid->SetCells(VTK_HEXAHEDRON, hexaArray);
if(quadTetraArray->GetNumberOfCells()>0)
grid->SetCells(VTK_QUADRATIC_TETRA, quadTetraArray);
if(quadHexaArray->GetNumberOfCells()>0)
grid->SetCells(VTK_QUADRATIC_HEXAHEDRON, quadHexaArray);
@ -382,11 +382,11 @@ void exportFemMeshCells(vtkSmartPointer<vtkUnstructuredGrid> grid, const SMDS_Vo
void FemVTKTools::exportVTKMesh(const FemMesh* mesh, vtkSmartPointer<vtkUnstructuredGrid> grid)
{
SMESH_Mesh* smesh = const_cast<SMESH_Mesh*>(mesh->getSMesh());
SMESHDS_Mesh* meshDS = smesh->GetMeshDS();
const SMDS_MeshInfo& info = meshDS->GetMeshInfo();
//start with the nodes
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
SMDS_NodeIteratorPtr aNodeIter = meshDS->nodesIterator();
@ -409,11 +409,11 @@ void FemVTKTools::exportVTKMesh(const FemMesh* mesh, vtkSmartPointer<vtkUnstruct
void FemVTKTools::writeVTKMesh(const char* filename, const FemMesh* mesh)
{
Base::TimeInfo Start;
Base::Console().Log("Start: write FemMesh from VTK unstructuredGrid ======================\n");
Base::FileInfo f(filename);
vtkSmartPointer<vtkUnstructuredGrid> grid = vtkSmartPointer<vtkUnstructuredGrid>::New();
exportVTKMesh(mesh, grid);
//vtkSmartPointer<vtkDataSet> dataset = vtkDataSet::SafeDownCast(grid);
@ -426,7 +426,7 @@ void FemVTKTools::writeVTKMesh(const char* filename, const FemMesh* mesh)
else{
Base::Console().Error("file name extension is not supported to write VTK\n");
}
Base::Console().Log(" %f: Done \n",Base::TimeInfo::diffTimeF(Start, Base::TimeInfo()));
}
@ -487,7 +487,7 @@ App::DocumentObject* FemVTKTools::readFluidicResult(const char* filename, App::D
Base::TimeInfo Start;
Base::Console().Log("Start: read FemResult with FemMesh from VTK file ======================\n");
Base::FileInfo f(filename);
vtkSmartPointer<vtkDataSet> ds;
if(f.hasExtension("vtu"))
{
@ -501,7 +501,7 @@ App::DocumentObject* FemVTKTools::readFluidicResult(const char* filename, App::D
{
Base::Console().Error("file name extension is not supported\n");
}
App::Document* pcDoc = App::GetApplication().getActiveDocument();
if(!pcDoc)
{
@ -532,12 +532,12 @@ App::DocumentObject* FemVTKTools::readFluidicResult(const char* filename, App::D
static_cast<PropertyFemMesh*>(mesh->getPropertyByName("FemMesh"))->setValue(*fmesh);
static_cast<App::PropertyLink*>(result->getPropertyByName("Mesh"))->setValue(mesh);
// PropertyLink is the property type to store DocumentObject pointer
importFluidicResult(dataset, result);
pcDoc->recompute();
Base::Console().Log(" %f: Done \n", Base::TimeInfo::diffTimeF(Start, Base::TimeInfo()));
return result;
}
@ -561,12 +561,12 @@ void FemVTKTools::writeResult(const char* filename, const App::DocumentObject* r
Base::TimeInfo Start;
Base::Console().Log("Start: write FemResult or CfdResult to VTK unstructuredGrid dataset =======\n");
Base::FileInfo f(filename);
vtkSmartPointer<vtkUnstructuredGrid> grid = vtkSmartPointer<vtkUnstructuredGrid>::New();
App::DocumentObject* mesh = static_cast<App::PropertyLink*>(res->getPropertyByName("Mesh"))->getValue();
const FemMesh& fmesh = static_cast<PropertyFemMesh*>(mesh->getPropertyByName("FemMesh"))->getValue();
FemVTKTools::exportVTKMesh(&fmesh, grid);
if(res->getPropertyByName("Velocity")){
FemVTKTools::exportFluidicResult(res, grid);
}
@ -576,7 +576,7 @@ void FemVTKTools::writeResult(const char* filename, const App::DocumentObject* r
else{
return;
}
//vtkSmartPointer<vtkDataSet> dataset = vtkDataSet::SafeDownCast(grid);
if(f.hasExtension("vtu")){
writeVTKFile<vtkXMLUnstructuredGridWriter>(filename, grid);
@ -587,7 +587,7 @@ void FemVTKTools::writeResult(const char* filename, const App::DocumentObject* r
else{
Base::Console().Error("file name extension is not supported to write VTK\n");
}
Base::Console().Log(" %f: Done \n",Base::TimeInfo::diffTimeF(Start, Base::TimeInfo()));
}
@ -604,7 +604,7 @@ void FemVTKTools::importFluidicResult(vtkSmartPointer<vtkDataSet> dataset, App::
vars["TurbulenceEnergy"] = "k";
vars["TurbulenceDissipationRate"] = "epsilon";
vars["TurbulenceSpecificDissipation"] = "omega";
const int max_var_index = 11;
std::vector<double> stats(3*max_var_index, 0.0);
@ -620,10 +620,10 @@ void FemVTKTools::importFluidicResult(vtkSmartPointer<vtkDataSet> dataset, App::
varids["TurbulenceDissipationRate"] = 8;
//varids["TurbulenceThermalDiffusivity"] = 9;
//varids["TurbulenceSpecificDissipation"] = 10;
double ts = 0.0; // t=0.0 for static simulation
static_cast<App::PropertyFloat*>(res->getPropertyByName("Time"))->setValue(ts);
vtkSmartPointer<vtkPointData> pd = dataset->GetPointData();
const vtkIdType nPoints = dataset->GetNumberOfPoints();
if(pd->GetNumberOfArrays() == 0) {
@ -631,7 +631,7 @@ void FemVTKTools::importFluidicResult(vtkSmartPointer<vtkDataSet> dataset, App::
// if pointData is empty, data may be in cellDate, cellData -> pointData interpolation is possible in VTK
return;
}
std::vector<long> nodeIds(nPoints);
vtkSmartPointer<vtkDataArray> vel = pd->GetArray(vars["Velocity"]);
if(nPoints && vel && vel->GetNumberOfComponents() == 3) {
@ -692,7 +692,7 @@ void FemVTKTools::importFluidicResult(vtkSmartPointer<vtkDataSet> dataset, App::
stats[index*3] = vmin;
stats[index*3 + 2] = vmax;
stats[index*3 + 1] = vmean/nPoints;
Base::Console().Message("field \"%s\" has been loaded \n", kv.first);
}
}
@ -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

View File

@ -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

View File

@ -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:
FreeCAD.Console.PrintError(" A group with this name exists already.\n")
else:
print(' NO group meshing.')
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

View 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
# @}

View File

@ -995,54 +995,43 @@ 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
elements = []
stype = None
if m.References:
for r in m.References:
parent = r[0]
childs = r[1]
# print(parent)
# print(childs)
for child in childs:
ref_shape = get_element(parent, child) # the method getElement(element) does not return Solid elements
if not stype:
stype = ref_shape.ShapeType
elif stype != ref_shape.ShapeType:
FreeCAD.Console.PrintError('Error, two refschapes in References with different ShapeTypes.\n')
# print(ref_shape)
found_element = find_element_in_shape(aShape, ref_shape)
if found_element is not None:
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(' ' + r[0].Name)
group_elements[key] = sorted(elements)
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, aShape)
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, aShape)
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])
@ -1051,6 +1040,37 @@ def get_analysis_group_elements(aAnalysis, aPart):
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
for r in obj.References:
parent = r[0]
childs = r[1]
# print(parent)
# print(childs)
for child in childs:
ref_shape = get_element(parent, child) # the method getElement(element) does not return Solid elements
if not stype:
stype = ref_shape.ShapeType
elif stype != ref_shape.ShapeType:
FreeCAD.Console.PrintError('Error, two refschapes in References with different ShapeTypes.\n')
# print(ref_shape)
found_element = find_element_in_shape(aShape, ref_shape)
if found_element is not None:
elements.append(found_element)
else:
FreeCAD.Console.PrintError('Problem: No element found for: ' + str(ref_shape) + '\n')
print(' ' + obj.Name)
print(' ' + str(obj.References))
print(' ' + r[0].Name)
return (key, sorted(elements))
def get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape):
'''get the elementIDs if the Reference shape is empty
see get_analysis_group_elements() for more informatations

View File

@ -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"

View File

@ -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"

View File

@ -54,6 +54,7 @@ class FemWorkbench (Workbench):
import _CommandFEMMesh2Mesh
import _CommandMeshGmshFromShape
import _CommandMeshNetgenFromShape
import _CommandMeshGroup
import _CommandMeshRegion
import _CommandAnalysis
import _CommandShellThickness

View 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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Selection&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>

View File

@ -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>

View 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())

View File

@ -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

View 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

View 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)

View File

@ -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

View File

@ -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:

View 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

View File

@ -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

View File

@ -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):

View File

@ -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>

View File

@ -37,18 +37,18 @@ if FreeCAD.GuiUp:
#-------------------------- translation-related code ----------------------------------------
#(see forum thread "A new Part tool is being born... JoinFeatures!"
#http://forum.freecadweb.org/viewtopic.php?f=22&t=11112&start=30#p90239 )
try:
_fromUtf8 = QtCore.QString.fromUtf8
except Exception:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
try:
_fromUtf8 = QtCore.QString.fromUtf8
except Exception:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
#--------------------------/translation-related code ----------------------------------------
def getIconPath(icon_dot_svg):

View File

@ -99,7 +99,7 @@ public:
~TaskCheckGeometryResults();
QString getShapeContentString();
private slots:
private Q_SLOTS:
void currentRowChanged (const QModelIndex &current, const QModelIndex &previous);
private:

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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>

View 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

View File

@ -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"]

View File

@ -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):

View 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())

View File

@ -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,14 +3253,34 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
Base::Vector3d p1b = lineSeg1->getEndPoint();
Base::Vector3d p2a = lineSeg2->getStartPoint();
Base::Vector3d p2b = lineSeg2->getEndPoint();
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();
if (tmp < length) {
length = tmp;
PosId1 = i ? Sketcher::start : Sketcher::end;
PosId2 = j ? Sketcher::start : Sketcher::end;
// 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 = Base::DistanceP2((j?p2a:p2b), (i?p1a:p1b));
if (tmp < length) {
length = tmp;
PosId1 = i ? Sketcher::start : Sketcher::end;
PosId2 = j ? Sketcher::start : Sketcher::end;
}
}
}
}
@ -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);

View File

@ -1,17 +1,17 @@
/****************************************************************************
**
** This file is part of a Qt Solutions component.
**
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Solutions Commercial License Agreement provided
** with the Software or, alternatively, in accordance with the terms
** contained in a written agreement between you and Nokia.
**
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
@ -19,29 +19,29 @@
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** Please note Third Party Software included with Qt Solutions may impose
** additional restrictions and it is the user's responsibility to ensure
** that they have met the licensing requirements of the GPL, LGPL, or Qt
** Solutions Commercial license and the relevant license of the Third
** Party Software they are using.
**
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**
****************************************************************************/
#include <QApplication>
@ -169,7 +169,7 @@ class ColorPickerItem : public QFrame
public:
ColorPickerItem(const QColor &color = Qt::white, const QString &text = QString::null,
QWidget *parent = 0);
QWidget *parent = 0);
~ColorPickerItem();
QColor color() const;
@ -181,7 +181,7 @@ signals:
void clicked();
void selected();
public slots:
public Q_SLOTS:
void setColor(const QColor &color, const QString &text = QString());
protected:
@ -205,7 +205,7 @@ class ColorPickerPopup : public QFrame
public:
ColorPickerPopup(int width, bool withColorDialog,
QWidget *parent = 0);
QWidget *parent = 0);
~ColorPickerPopup();
void insertColor(const QColor &col, const QString &text, int index);
@ -217,17 +217,17 @@ public:
ColorPickerItem *find(const QColor &col) const;
QColor color(int index) const;
void setLastSel(const QColor & col);
signals:
void selected(const QColor &);
void hid();
public slots:
public Q_SLOTS:
void getColorFromDialog();
protected slots:
protected Q_SLOTS:
void updateSelected();
protected:
@ -268,7 +268,7 @@ private:
\sa QFrame
*/
QtColorPicker::QtColorPicker(QWidget *parent,
int cols, bool enableColorDialog)
int cols, bool enableColorDialog)
: QPushButton(parent), popup(0), withColorDialog(enableColorDialog)
{
setFocusPolicy(Qt::StrongFocus);
@ -288,7 +288,7 @@ QtColorPicker::QtColorPicker(QWidget *parent,
// Create color grid popup and connect to it.
popup = new ColorPickerPopup(cols, withColorDialog, this);
connect(popup, SIGNAL(selected(const QColor &)),
SLOT(setCurrentColor(const QColor &)));
SLOT(setCurrentColor(const QColor &)));
connect(popup, SIGNAL(hid()), SLOT(popupClosed()));
// Connect this push button's pressed() signal.
@ -434,18 +434,18 @@ 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())
return;
return;
ColorPickerItem *item = popup->find(color);
if (!item) {
insertColor(color, tr("Custom"));
item = popup->find(color);
insertColor(color, tr("Custom"));
item = popup->find(color);
}
popup->setLastSel(color);
col = color;
@ -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);
}
/*!
@ -471,9 +471,9 @@ void QtColorPicker::insertColor(const QColor &color, const QString &text, int in
{
popup->insertColor(color, text, index);
if (!firstInserted) {
col = color;
setText(text);
firstInserted = true;
col = color;
setText(text);
firstInserted = true;
}
}
@ -504,7 +504,7 @@ bool QtColorPicker::colorDialogEnabled() const
\code
void Drawer::mouseReleaseEvent(QMouseEvent *e)
{
if (e->button() & RightButton) {
if (e->button() & RightButton) {
QColor color = QtColorPicker::getColor(mapToGlobal(e->pos()));
}
}
@ -542,7 +542,7 @@ QColor QtColorPicker::getColor(const QPoint &point, bool allowCustomColors)
Constructs the popup widget.
*/
ColorPickerPopup::ColorPickerPopup(int width, bool withColorDialog,
QWidget *parent)
QWidget *parent)
: QFrame(parent, Qt::Popup)
{
setFrameStyle(QFrame::StyledPanel);
@ -553,13 +553,13 @@ ColorPickerPopup::ColorPickerPopup(int width, bool withColorDialog,
cols = width;
if (withColorDialog) {
moreButton = new ColorPickerButton(this);
moreButton->setFixedWidth(24);
moreButton->setFixedHeight(21);
moreButton->setFrameRect(QRect(2, 2, 20, 17));
connect(moreButton, SIGNAL(clicked()), SLOT(getColorFromDialog()));
moreButton = new ColorPickerButton(this);
moreButton->setFixedWidth(24);
moreButton->setFixedHeight(21);
moreButton->setFrameRect(QRect(2, 2, 20, 17));
connect(moreButton, SIGNAL(clicked()), SLOT(getColorFromDialog()));
} else {
moreButton = 0;
moreButton = 0;
}
eventLoop = 0;
@ -586,8 +586,8 @@ ColorPickerPopup::~ColorPickerPopup()
ColorPickerItem *ColorPickerPopup::find(const QColor &col) const
{
for (int i = 0; i < items.size(); ++i) {
if (items.at(i) && items.at(i)->color() == col)
return items.at(i);
if (items.at(i) && items.at(i)->color() == col)
return items.at(i);
}
return 0;
@ -626,7 +626,7 @@ void ColorPickerPopup::insertColor(const QColor &col, const QString &text, int i
connect(item, SIGNAL(selected()), SLOT(updateSelected()));
if (index == -1)
index = items.count();
index = items.count();
items.insert((unsigned int)index, item);
regenerateGrid();
@ -667,19 +667,19 @@ void ColorPickerPopup::updateSelected()
QLayoutItem *layoutItem;
int i = 0;
while ((layoutItem = grid->itemAt(i)) != 0) {
QWidget *w = layoutItem->widget();
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *litem = reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
if (litem != sender())
litem->setSelected(false);
}
++i;
QWidget *w = layoutItem->widget();
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *litem = reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
if (litem != sender())
litem->setSelected(false);
}
++i;
}
if (sender() && sender()->inherits("ColorPickerItem")) {
ColorPickerItem *item = (ColorPickerItem *)sender();
lastSel = item->color();
emit selected(item->color());
ColorPickerItem *item = (ColorPickerItem *)sender();
lastSel = item->color();
Q_EMIT selected(item->color());
}
hide();
@ -691,7 +691,7 @@ void ColorPickerPopup::updateSelected()
void ColorPickerPopup::mouseReleaseEvent(QMouseEvent *e)
{
if (!rect().contains(e->pos()))
hide();
hide();
}
/*! \internal
@ -705,96 +705,96 @@ void ColorPickerPopup::keyPressEvent(QKeyEvent *e)
bool foundFocus = false;
for (int j = 0; !foundFocus && j < grid->rowCount(); ++j) {
for (int i = 0; !foundFocus && i < grid->columnCount(); ++i) {
if (widgetAt[j][i] && widgetAt[j][i]->hasFocus()) {
curRow = j;
curCol = i;
foundFocus = true;
break;
}
}
for (int i = 0; !foundFocus && i < grid->columnCount(); ++i) {
if (widgetAt[j][i] && widgetAt[j][i]->hasFocus()) {
curRow = j;
curCol = i;
foundFocus = true;
break;
}
}
}
switch (e->key()) {
case Qt::Key_Left:
if (curCol > 0) --curCol;
else if (curRow > 0) { --curRow; curCol = grid->columnCount() - 1; }
break;
case Qt::Key_Right:
if (curCol < grid->columnCount() - 1 && widgetAt[curRow][curCol + 1]) ++curCol;
else if (curRow < grid->rowCount() - 1) { ++curRow; curCol = 0; }
break;
case Qt::Key_Up:
if (curRow > 0) --curRow;
else curCol = 0;
break;
case Qt::Key_Down:
if (curRow < grid->rowCount() - 1) {
QWidget *w = widgetAt[curRow + 1][curCol];
if (w) {
++curRow;
} else for (int i = 1; i < grid->columnCount(); ++i) {
if (!widgetAt[curRow + 1][i]) {
curCol = i - 1;
++curRow;
break;
}
}
}
break;
case Qt::Key_Space:
case Qt::Key_Return:
case Qt::Key_Enter: {
QWidget *w = widgetAt[curRow][curCol];
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
wi->setSelected(true);
case Qt::Key_Left:
if (curCol > 0) --curCol;
else if (curRow > 0) { --curRow; curCol = grid->columnCount() - 1; }
break;
case Qt::Key_Right:
if (curCol < grid->columnCount() - 1 && widgetAt[curRow][curCol + 1]) ++curCol;
else if (curRow < grid->rowCount() - 1) { ++curRow; curCol = 0; }
break;
case Qt::Key_Up:
if (curRow > 0) --curRow;
else curCol = 0;
break;
case Qt::Key_Down:
if (curRow < grid->rowCount() - 1) {
QWidget *w = widgetAt[curRow + 1][curCol];
if (w) {
++curRow;
} else for (int i = 1; i < grid->columnCount(); ++i) {
if (!widgetAt[curRow + 1][i]) {
curCol = i - 1;
++curRow;
break;
}
}
}
break;
case Qt::Key_Space:
case Qt::Key_Return:
case Qt::Key_Enter: {
QWidget *w = widgetAt[curRow][curCol];
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
wi->setSelected(true);
QLayoutItem *layoutItem;
QLayoutItem *layoutItem;
int i = 0;
while ((layoutItem = grid->itemAt(i)) != 0) {
QWidget *w = layoutItem->widget();
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *litem
= reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
if (litem != wi)
litem->setSelected(false);
}
++i;
}
while ((layoutItem = grid->itemAt(i)) != 0) {
QWidget *w = layoutItem->widget();
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *litem
= reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
if (litem != wi)
litem->setSelected(false);
}
++i;
}
lastSel = wi->color();
emit selected(wi->color());
hide();
} else if (w && w->inherits("QPushButton")) {
ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
wi->setSelected(true);
lastSel = wi->color();
Q_EMIT selected(wi->color());
hide();
} else if (w && w->inherits("QPushButton")) {
ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
wi->setSelected(true);
QLayoutItem *layoutItem;
QLayoutItem *layoutItem;
int i = 0;
while ((layoutItem = grid->itemAt(i)) != 0) {
QWidget *w = layoutItem->widget();
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *litem
= reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
if (litem != wi)
litem->setSelected(false);
}
++i;
}
while ((layoutItem = grid->itemAt(i)) != 0) {
QWidget *w = layoutItem->widget();
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *litem
= reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
if (litem != wi)
litem->setSelected(false);
}
++i;
}
lastSel = wi->color();
emit selected(wi->color());
hide();
}
}
break;
lastSel = wi->color();
Q_EMIT selected(wi->color());
hide();
}
}
break;
case Qt::Key_Escape:
hide();
break;
default:
e->ignore();
break;
default:
e->ignore();
break;
}
widgetAt[curRow][curCol]->setFocus();
@ -806,12 +806,12 @@ void ColorPickerPopup::keyPressEvent(QKeyEvent *e)
void ColorPickerPopup::hideEvent(QHideEvent *e)
{
if (eventLoop) {
eventLoop->exit();
eventLoop->exit();
}
setFocus();
emit hid();
Q_EMIT hid();
QFrame::hideEvent(e);
}
@ -832,23 +832,23 @@ void ColorPickerPopup::showEvent(QShowEvent *)
{
bool foundSelected = false;
for (int i = 0; i < grid->columnCount(); ++i) {
for (int j = 0; j < grid->rowCount(); ++j) {
QWidget *w = widgetAt[j][i];
if (w && w->inherits("ColorPickerItem")) {
if (((ColorPickerItem *)w)->isSelected()) {
w->setFocus();
foundSelected = true;
break;
}
}
}
for (int j = 0; j < grid->rowCount(); ++j) {
QWidget *w = widgetAt[j][i];
if (w && w->inherits("ColorPickerItem")) {
if (((ColorPickerItem *)w)->isSelected()) {
w->setFocus();
foundSelected = true;
break;
}
}
}
}
if (!foundSelected) {
if (items.count() == 0)
setFocus();
else
widgetAt[0][0]->setFocus();
if (items.count() == 0)
setFocus();
else
widgetAt[0][0]->setFocus();
}
}
@ -861,7 +861,7 @@ void ColorPickerPopup::regenerateGrid()
int columns = cols;
if (columns == -1)
columns = (int) ceil(sqrt((float) items.count()));
columns = (int) ceil(sqrt((float) items.count()));
// When the number of columns grows, the number of rows will
// fall. There's no way to shrink a grid, so we create a new
@ -884,8 +884,8 @@ void ColorPickerPopup::regenerateGrid()
}
if (moreButton) {
grid->addWidget(moreButton, crow, ccol);
widgetAt[crow][ccol] = moreButton;
grid->addWidget(moreButton, crow, ccol);
widgetAt[crow][ccol] = moreButton;
}
updateGeometry();
}
@ -901,12 +901,12 @@ void ColorPickerPopup::getColorFromDialog()
//QRgb rgb = QColorDialog::getRgba(lastSel.rgba(), &ok, parentWidget());
QColor col = QColorDialog::getColor(lastSel,parentWidget(),0,QColorDialog::ShowAlphaChannel);
if (!col.isValid())
return;
return;
//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; }
@ -916,7 +916,7 @@ void ColorPickerPopup::setLastSel(const QColor & col) { lastSel = col; }
whose name is set to \a text.
*/
ColorPickerItem::ColorPickerItem(const QColor &color, const QString &text,
QWidget *parent)
QWidget *parent)
: QFrame(parent), c(color), t(text), sel(false)
{
setToolTip(t);
@ -994,7 +994,7 @@ void ColorPickerItem::mouseMoveEvent(QMouseEvent *)
void ColorPickerItem::mouseReleaseEvent(QMouseEvent *)
{
sel = true;
emit selected();
Q_EMIT selected();
}
/*!
@ -1018,14 +1018,14 @@ void ColorPickerItem::paintEvent(QPaintEvent *)
p.setPen( QPen( Qt::gray, 0, Qt::SolidLine ) );
if (sel)
p.drawRect(1, 1, w - 3, h - 3);
p.drawRect(1, 1, w - 3, h - 3);
p.setPen( QPen( Qt::black, 0, Qt::SolidLine ) );
p.drawRect(3, 3, w - 7, h - 7);
p.fillRect(QRect(4, 4, w - 8, h - 8), QBrush(c));
if (hasFocus())
p.drawRect(0, 0, w - 1, h - 1);
p.drawRect(0, 0, w - 1, h - 1);
}
/*!
@ -1062,7 +1062,7 @@ void ColorPickerButton::mouseReleaseEvent(QMouseEvent *)
{
setFrameShadow(Raised);
repaint();
emit clicked();
Q_EMIT clicked();
}
/*!
@ -1071,15 +1071,15 @@ void ColorPickerButton::mouseReleaseEvent(QMouseEvent *)
void ColorPickerButton::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Up
|| e->key() == Qt::Key_Down
|| e->key() == Qt::Key_Left
|| e->key() == Qt::Key_Right) {
qApp->sendEvent(parent(), e);
|| e->key() == Qt::Key_Down
|| e->key() == Qt::Key_Left
|| e->key() == Qt::Key_Right) {
qApp->sendEvent(parent(), e);
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return) {
setFrameShadow(Sunken);
update();
setFrameShadow(Sunken);
update();
} else {
QFrame::keyPressEvent(e);
QFrame::keyPressEvent(e);
}
}
@ -1089,16 +1089,16 @@ void ColorPickerButton::keyPressEvent(QKeyEvent *e)
void ColorPickerButton::keyReleaseEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Up
|| e->key() == Qt::Key_Down
|| e->key() == Qt::Key_Left
|| e->key() == Qt::Key_Right) {
qApp->sendEvent(parent(), e);
|| e->key() == Qt::Key_Down
|| e->key() == Qt::Key_Left
|| e->key() == Qt::Key_Right) {
qApp->sendEvent(parent(), e);
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return) {
setFrameShadow(Raised);
repaint();
emit clicked();
setFrameShadow(Raised);
repaint();
Q_EMIT clicked();
} else {
QFrame::keyReleaseEvent(e);
QFrame::keyReleaseEvent(e);
}
}
@ -1144,8 +1144,8 @@ void ColorPickerButton::paintEvent(QPaintEvent *e)
p.drawRect(r.center().x() + offset , r.center().y() + offset, 1, 1);
p.drawRect(r.center().x() + offset + 4, r.center().y() + offset, 1, 1);
if (hasFocus()) {
p.setPen( QPen( Qt::black, 0, Qt::SolidLine ) );
p.drawRect(0, 0, width() - 1, height() - 1);
p.setPen( QPen( Qt::black, 0, Qt::SolidLine ) );
p.drawRect(0, 0, width() - 1, height() - 1);
}
p.end();

View File

@ -182,7 +182,7 @@ void FileChooser::chooseFile()
if (!fn.isEmpty()) {
lineEdit->setText(fn);
emit fileNameSelected(fn);
Q_EMIT fileNameSelected(fn);
}
}
@ -595,9 +595,9 @@ QAbstractSpinBox::StepEnabled QuantitySpinBox::stepEnabled() const
}
return ret;
}
void QuantitySpinBox::stepBy(int steps)
{
void QuantitySpinBox::stepBy(int steps)
{
double step = StepSize * steps;
double val = Value + step;
if (val > Maximum)
@ -607,7 +607,7 @@ void QuantitySpinBox::stepBy(int steps)
lineEdit()->setText(QString::fromUtf8("%L1 %2").arg(val).arg(UnitStr));
update();
}
}
void QuantitySpinBox::setUnitText(QString str)
{
@ -792,9 +792,9 @@ public:
UIntSpinBox::UIntSpinBox (QWidget* parent)
: QSpinBox (parent)
{
d = new UIntSpinBoxPrivate;
d = new UIntSpinBoxPrivate;
d->mValidator = new UnsignedValidator(this->minimum(), this->maximum(), this);
connect(this, SIGNAL(valueChanged(int)),
connect(this, SIGNAL(valueChanged(int)),
this, SLOT(valueChange(int)));
setRange(0, 99);
setValue(0);
@ -802,7 +802,7 @@ UIntSpinBox::UIntSpinBox (QWidget* parent)
}
UIntSpinBox::~UIntSpinBox()
{
{
delete d->mValidator;
delete d; d = 0;
}
@ -1032,7 +1032,7 @@ void ColorButton::onChooseColor()
if ( c.isValid() )
{
setColor( c );
emit changed();
Q_EMIT changed();
}
}

View File

@ -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)