Merge branch 'master' into bugfix/dogbone-on-straight-edges-and-noop-moves
This commit is contained in:
@@ -38,7 +38,7 @@
|
||||
#include <QPushButton>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <App/Application.h>
|
||||
//#include <App/Parameter.h>
|
||||
@@ -54,7 +54,7 @@ QByteArray toParamEntry(QString name)
|
||||
|
||||
void DlgCheckableMessageBox::showMessage(const QString& header, const QString& message, bool check, const QString& checkText)
|
||||
{
|
||||
bool checked = App::GetApplication().GetParameterGroupByPath( QByteArray("User parameter:BaseApp/CheckMessages"))->GetBool(toParamEntry(header));
|
||||
bool checked = App::GetApplication().GetParameterGroupByPath(QByteArray("User parameter:BaseApp/CheckMessages"))->GetBool(toParamEntry(header));
|
||||
|
||||
if (!checked) {
|
||||
DlgCheckableMessageBox *mb = new DlgCheckableMessageBox(Gui::getMainWindow());
|
||||
@@ -69,7 +69,25 @@ void DlgCheckableMessageBox::showMessage(const QString& header, const QString& m
|
||||
mb->show();
|
||||
}
|
||||
}
|
||||
void DlgCheckableMessageBox::showMessage(const QString& header, const QString& message, const QString& prefPath, const QString& paramEntry,
|
||||
bool entryDefault, bool check, const QString& checkText)
|
||||
{
|
||||
bool checked = App::GetApplication().GetParameterGroupByPath(prefPath.toLatin1())->GetBool(paramEntry.toLatin1(), entryDefault);
|
||||
|
||||
if(checked == entryDefault) {
|
||||
auto mb = new Gui::Dialog::DlgCheckableMessageBox(Gui::getMainWindow());
|
||||
mb->setWindowTitle(header);
|
||||
mb->setIconPixmap(QMessageBox::standardIcon(QMessageBox::Warning));
|
||||
mb->setText(message);
|
||||
mb->setPrefPath(prefPath);
|
||||
mb->setPrefEntry(paramEntry);
|
||||
mb->setCheckBoxText(checkText);
|
||||
mb->setChecked(check);
|
||||
mb->setStandardButtons(QDialogButtonBox::Ok);
|
||||
mb->setDefaultButton(QDialogButtonBox::Ok);
|
||||
mb->show();
|
||||
}
|
||||
}
|
||||
|
||||
struct DlgCheckableMessageBoxPrivate {
|
||||
DlgCheckableMessageBoxPrivate() : clickedButton(0) {}
|
||||
@@ -80,7 +98,8 @@ struct DlgCheckableMessageBoxPrivate {
|
||||
|
||||
DlgCheckableMessageBox::DlgCheckableMessageBox(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
m_d(new DlgCheckableMessageBoxPrivate)
|
||||
m_d(new DlgCheckableMessageBoxPrivate),
|
||||
prefPath(QLatin1String("User parameter:BaseApp/CheckMessages"))
|
||||
{
|
||||
setModal(true);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
@@ -99,10 +118,14 @@ DlgCheckableMessageBox::~DlgCheckableMessageBox()
|
||||
void DlgCheckableMessageBox::setPrefEntry(const QString& entry)
|
||||
{
|
||||
paramEntry = toParamEntry(entry);
|
||||
bool checked = App::GetApplication().GetParameterGroupByPath(QByteArray("User parameter:BaseApp/CheckMessages"))->GetBool(paramEntry);
|
||||
bool checked = App::GetApplication().GetParameterGroupByPath(prefPath.toLatin1())->GetBool(paramEntry);
|
||||
setChecked(checked);
|
||||
}
|
||||
|
||||
void DlgCheckableMessageBox::setPrefPath(const QString& path)
|
||||
{
|
||||
prefPath = path;
|
||||
}
|
||||
|
||||
void DlgCheckableMessageBox::slotClicked(QAbstractButton *b)
|
||||
{
|
||||
@@ -198,14 +221,14 @@ void DlgCheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s
|
||||
void DlgCheckableMessageBox::accept()
|
||||
{
|
||||
if(!paramEntry.isEmpty())
|
||||
App::GetApplication().GetParameterGroupByPath( QByteArray("User parameter:BaseApp/CheckMessages"))->SetBool(paramEntry,isChecked());
|
||||
App::GetApplication().GetParameterGroupByPath(prefPath.toLatin1())->SetBool(paramEntry,isChecked());
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void DlgCheckableMessageBox::reject()
|
||||
{
|
||||
if(!paramEntry.isEmpty())
|
||||
App::GetApplication().GetParameterGroupByPath( QByteArray("User parameter:BaseApp/CheckMessages"))->SetBool(paramEntry,isChecked());
|
||||
App::GetApplication().GetParameterGroupByPath(prefPath.toLatin1())->SetBool(paramEntry,isChecked());
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ public:
|
||||
|
||||
void setPrefEntry(const QString& entry);
|
||||
|
||||
void setPrefPath(const QString& path);
|
||||
|
||||
virtual void accept();
|
||||
virtual void reject();
|
||||
|
||||
@@ -99,8 +101,15 @@ public:
|
||||
// Conversion convenience
|
||||
static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton);
|
||||
|
||||
// convenient show method
|
||||
static void showMessage(const QString& header, const QString& message, bool check=false, const QString& checkText = QString::fromLatin1("Don't show me again"));
|
||||
/// convenient show method
|
||||
/// It shows a dialog with header and message provided and a checkbox in check state with the message provided.
|
||||
/// It uses a parameter in path "User parameter:BaseApp/CheckMessages" derived from the header test, defaulting to false,
|
||||
/// to store the status of the checkbox, when the user exits the modal dialog.
|
||||
static void showMessage(const QString& header, const QString& message, bool check = false, const QString& checkText = QString::fromLatin1("Don't show me again"));
|
||||
|
||||
/// Same as showMessage above, but it checks the specific preference path and parameter provided, defaulting to entryDefault value if the parameter is not present.
|
||||
static void showMessage(const QString& header, const QString& message, const QString& prefPath, const QString& paramEntry, bool entryDefault = false,
|
||||
bool check = false, const QString& checkText = QString::fromLatin1("Don't show me again"));
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotClicked(QAbstractButton *b);
|
||||
@@ -108,6 +117,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
DlgCheckableMessageBoxPrivate *m_d;
|
||||
QByteArray paramEntry;
|
||||
QString prefPath;
|
||||
};
|
||||
|
||||
} // namespace Dialog
|
||||
|
||||
@@ -25,9 +25,11 @@
|
||||
#define _SoFCSelectionAction_h
|
||||
|
||||
//#include <Inventor/SoAction.h>
|
||||
#include <Inventor/actions/SoGLRenderAction.h>
|
||||
#include <Inventor/actions/SoSubAction.h>
|
||||
#include <Inventor/events/SoSubEvent.h>
|
||||
#include <Inventor/actions/SoGLRenderAction.h>
|
||||
#include <Inventor/fields/SoSFColor.h>
|
||||
#include <Inventor/fields/SoSFString.h>
|
||||
#include <Inventor/SbColor.h>
|
||||
#include <vector>
|
||||
|
||||
@@ -101,7 +103,7 @@ public:
|
||||
SoFCEnableSelectionAction (const SbBool& sel);
|
||||
~SoFCEnableSelectionAction();
|
||||
|
||||
const SbBool& selection;
|
||||
SbBool selection;
|
||||
|
||||
static void initClass();
|
||||
static void finish(void);
|
||||
@@ -126,7 +128,7 @@ public:
|
||||
SoFCEnableHighlightAction (const SbBool& sel);
|
||||
~SoFCEnableHighlightAction();
|
||||
|
||||
const SbBool& highlight;
|
||||
SbBool highlight;
|
||||
|
||||
static void initClass();
|
||||
static void finish(void);
|
||||
@@ -151,7 +153,7 @@ public:
|
||||
SoFCSelectionColorAction (const SoSFColor& col);
|
||||
~SoFCSelectionColorAction();
|
||||
|
||||
const SoSFColor& selectionColor;
|
||||
SoSFColor selectionColor;
|
||||
|
||||
static void initClass();
|
||||
static void finish(void);
|
||||
@@ -176,7 +178,7 @@ public:
|
||||
SoFCHighlightColorAction (const SoSFColor& col);
|
||||
~SoFCHighlightColorAction();
|
||||
|
||||
const SoSFColor& highlightColor;
|
||||
SoSFColor highlightColor;
|
||||
|
||||
static void initClass();
|
||||
static void finish(void);
|
||||
@@ -201,7 +203,7 @@ public:
|
||||
SoFCDocumentAction (const SoSFString& docName);
|
||||
~SoFCDocumentAction();
|
||||
|
||||
const SoSFString& documentName;
|
||||
SoSFString documentName;
|
||||
|
||||
static void initClass();
|
||||
static void finish(void);
|
||||
|
||||
+226
-152
@@ -24,7 +24,9 @@ INSTALLATION
|
||||
WINDOWS = C:/[INSTALLATION_PATH]/FreeCAD/data/Gui/Stylesheets/
|
||||
LINUX = /home/[YOUR_USER_NAME]/.FreeCAD/Gui/Stylesheets/
|
||||
|
||||
============================================================================================================
|
||||
============================================================================================================
|
||||
THESE COLOURS WERE USED AS TEMP SCRATCHPAD FOR DESIGNING. PLEASE DISREGARD!
|
||||
|
||||
BACKGROUND (darker to lighter)
|
||||
black
|
||||
#1e1e1e
|
||||
@@ -143,6 +145,10 @@ QToolBox::tab:hover
|
||||
/*==================================================================================================
|
||||
QStatusBar
|
||||
==================================================================================================*/
|
||||
QStatusBar > QLabel {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
|
||||
QStatusBar::item {
|
||||
border: 1px solid #333333;
|
||||
@@ -220,7 +226,7 @@ QMenu QToolButton:pressed,
|
||||
QMenu QPushButton:selected,
|
||||
QMenu QToolButton:selected {
|
||||
color: white;
|
||||
background-color: #696969; /* same as QMenu::item:selected and QMenu::item:pressed */
|
||||
background-color: #557bb6; /* same as QMenu::item:selected and QMenu::item:pressed */
|
||||
}
|
||||
|
||||
QMenu QRadioButton:disabled,
|
||||
@@ -286,7 +292,7 @@ Group box
|
||||
QGroupBox {
|
||||
color: #bcbcbc;
|
||||
border:1px solid rgba(255,255,255,20); /* lighter than its own border-color */;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin-top: 10px;
|
||||
padding: 6px;
|
||||
background-color: rgba(255,255,255,0);
|
||||
@@ -316,7 +322,7 @@ QToolTip {
|
||||
background-color: #2a2a2a;
|
||||
/*opacity: 90%; doesn't correctly work */
|
||||
padding: 4px;
|
||||
border-radius: 2px; /* has no effect */
|
||||
border-radius: 1px; /* has no effect */
|
||||
}
|
||||
|
||||
|
||||
@@ -334,15 +340,15 @@ QDockWidget::title {
|
||||
text-align: center;
|
||||
background-color: #2a2a2a;
|
||||
border-bottom: 4px solid #333333; /* fix to simulate margin between this :title and tabs */ /* same as main background color */
|
||||
margin-left: 7px;
|
||||
margin-right: 7px;
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
QDockWidget::close-button,
|
||||
QDockWidget::float-button {
|
||||
border: none;
|
||||
background: transparent;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
subcontrol-origin: padding;
|
||||
subcontrol-position: right center;
|
||||
}
|
||||
@@ -369,7 +375,6 @@ QDockWidget::float-button:pressed {
|
||||
/* fix for Python Console (probably there is a smarter way to arrive to it) */
|
||||
QDockWidget > QFrame {
|
||||
background-color: #3c3c3c;
|
||||
|
||||
border: 6px solid #333333;
|
||||
}
|
||||
|
||||
@@ -385,12 +390,12 @@ QProgressBar:horizontal {
|
||||
text-align: center;
|
||||
border: 1px solid rgba(0,0,0,140);
|
||||
padding: 1px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
QProgressBar::chunk,
|
||||
QProgressBar::chunk:horizontal {
|
||||
background-color: #557BB6;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
|
||||
@@ -398,7 +403,7 @@ QProgressBar::chunk:horizontal {
|
||||
Scroll
|
||||
==================================================================================================*/
|
||||
QAbstractScrollArea {
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -425,7 +430,7 @@ QScrollBar::handle:horizontal:hover {
|
||||
|
||||
QScrollBar::handle:horizontal {
|
||||
min-width: 5px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 4px 15px;
|
||||
}
|
||||
|
||||
@@ -477,7 +482,7 @@ QScrollBar:vertical {
|
||||
|
||||
QScrollBar::handle:vertical {
|
||||
min-height: 24px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 15px 4px;
|
||||
}
|
||||
|
||||
@@ -667,7 +672,7 @@ QDialog#Gui__Dialog__DlgPreferences > QListView {
|
||||
|
||||
/* unique styles for sections inside Preferences */
|
||||
QDialog#Gui__Dialog__DlgPreferences > QListView::item {
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QDialog#Gui__Dialog__DlgPreferences > QListView::item:hover { /* Preference left icons*/
|
||||
@@ -687,7 +692,7 @@ Tab bar buttons
|
||||
QTabBar::close-button {
|
||||
subcontrol-origin: margin;
|
||||
subcontrol-position: center right; /* only works for Qt 4.6 and newer */;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
background-image: url(qss:images_dark-light/close_light.svg);
|
||||
background-position: center center;
|
||||
background-repeat: none;
|
||||
@@ -790,7 +795,7 @@ QTableView {
|
||||
selection-color: #ffffff;
|
||||
selection-background-color: #557BB6; /* should be similar to QListView::item selected background-color */
|
||||
show-decoration-selected: 1; /* make the selection span the entire width of the view */
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QListView::item:hover,
|
||||
@@ -821,7 +826,7 @@ Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QLabel:disabled {
|
||||
color: transparent;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
@@ -894,7 +899,7 @@ QTreeView > QWidget > QTimeEdit:down-button,
|
||||
QTreeView > QWidget > QDateEdit:down-button,
|
||||
QTreeView > QWidget > QDateTimeEdit:down-button,
|
||||
QTreeView > QWidget > Gui--ColorButton {
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
/* set focus colors to best viewing the editable fields */
|
||||
@@ -927,7 +932,7 @@ QTreeView > QWidget > QDateTimeEdit:read-only {
|
||||
/* Fix to correctly (not totally) draw QTextEdit on OSX at Page properties: "Page result", "Template" and "Editable Texts" */
|
||||
Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QWidget {
|
||||
min-height: 14px;
|
||||
border-radius: 2px; /* reset */
|
||||
border-radius: 1px; /* reset */
|
||||
}
|
||||
|
||||
|
||||
@@ -937,8 +942,8 @@ Header of tree and list views
|
||||
QHeaderView {
|
||||
color: #d2d2d2;
|
||||
background-color: #2a2a2a;
|
||||
border-top-left-radius: 2px; /* 1px less than its container */
|
||||
border-top-right-radius: 2px; /* 1px less than its container */
|
||||
border-top-left-radius: 1px; /* 1px less than its container */
|
||||
border-top-right-radius: 1px; /* 1px less than its container */
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
@@ -1220,7 +1225,7 @@ QToolBar > Gui--WorkbenchComboBox {
|
||||
selection-color: #ffffff;
|
||||
selection-background-color: #2a2a2a;
|
||||
border: 1px solid #2a2a2a;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
min-width: 50px; /* it ensures the default value is correctly displayed */
|
||||
min-height: 16px; /* important to be a pair number in order to up/down buttons to be divisible by two (if not set could create a blank line in Ubuntu. Its downside is that it's needed to reset it (min-width: 0px) on following elements that can't have it such as fields inside QToolBar and inside QTreeView (Property editor) */
|
||||
padding: 1px 2px; /* temporal: could don't be compatible with elements inside Tree/List view */
|
||||
@@ -1244,9 +1249,9 @@ QDateTimeEdit {
|
||||
color: #f5f5f5;
|
||||
background-color: #494949; /* lineedits and drop-downs */
|
||||
selection-color: #ffffff;
|
||||
selection-background-color: #2a2a2a;
|
||||
selection-background-color: #557bb6;
|
||||
border: 0px solid #2a2a2a;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
min-width: 50px; /* it ensures the default value is correctly displayed */
|
||||
min-height: 16px; /* important to be a pair number in order to up/down buttons to be divisible by two (if not set could create a blank line in Ubuntu. Its downside is that it's needed to reset it (min-width: 0px) on following elements that can't have it such as fields inside QToolBar and inside QTreeView (Property editor) */
|
||||
padding: 1px 2px; /* temporal: could don't be compatible with elements inside Tree/List view */
|
||||
@@ -1293,7 +1298,7 @@ QDateTimeEdit:focus {
|
||||
border-color: #333333;
|
||||
border: 1px;
|
||||
border-right-color: #557BB6; /* same as up/down or drop-down button color */
|
||||
background-color: #557bb6;
|
||||
background-color: #494949;
|
||||
}
|
||||
|
||||
QComboBox:disabled,
|
||||
@@ -1461,8 +1466,8 @@ QComboBox::drop-down {
|
||||
subcontrol-origin: border; /* important */
|
||||
subcontrol-position: top right;
|
||||
width: 20px;
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
border-top-right-radius: 1px;
|
||||
border-bottom-right-radius: 1px;
|
||||
}
|
||||
|
||||
QComboBox::drop-down:on,
|
||||
@@ -1505,109 +1510,156 @@ QComboBox QAbstractItemView {
|
||||
/*==================================================================================================
|
||||
Push button
|
||||
==================================================================================================*/
|
||||
QPushButton#inspectButton {
|
||||
background-color: #2a2a2a;
|
||||
border-bottom: 2px solid #1e1e1e;
|
||||
min-height: 16px;
|
||||
}
|
||||
|
||||
QPushButton:focus#inspectButton,
|
||||
QPushButton:hover#inspectButton {
|
||||
background-color: #557bb6;
|
||||
border: -2px solid #557bb6;
|
||||
}
|
||||
|
||||
QPushButton:checked#inspectButton {
|
||||
background-color: #557bb6;
|
||||
border-bottom: solid #557bb6;
|
||||
}
|
||||
|
||||
QPushButton:pressed#inspectButton {
|
||||
background-color: #557bb6;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
QPushButton#NavigationIndicator {
|
||||
background-color: #557bb6;
|
||||
min-height: 16px;
|
||||
border: 2px solid #557bb6;
|
||||
}
|
||||
|
||||
QPushButton:hover#NavigationIndicator {
|
||||
border: -2px solid #557bb6;
|
||||
}
|
||||
|
||||
QPushButton#buttonAddLevel {
|
||||
margin-left:10px;
|
||||
}
|
||||
|
||||
QPushButton#buttonRename {
|
||||
margin-right:10px;
|
||||
}
|
||||
|
||||
QPushButton#buttonAddLevel,
|
||||
QPushButton#buttonAddProxy,
|
||||
QPushButton#buttonDelete,
|
||||
QPushButton#buttonToggle,
|
||||
QPushButton#buttonIsolate,
|
||||
QPushButton#buttonSaveView,
|
||||
QPushButton#buttonRename {
|
||||
color: #f5f5f5;
|
||||
max-width: 100%;
|
||||
min-width: 16px;
|
||||
min-height: 24px;
|
||||
padding: 4px;
|
||||
background-color: #333333;
|
||||
border: 1px #557bb6;
|
||||
}
|
||||
|
||||
QPushButton:hover#buttonAddLevel,
|
||||
QPushButton:hover#buttonAddProxy,
|
||||
QPushButton:hover#buttonDelete,
|
||||
QPushButton:hover#buttonToggle,
|
||||
QPushButton:hover#buttonIsolate,
|
||||
QPushButton:hover#buttonSaveView,
|
||||
QPushButton:hover#buttonRename {
|
||||
color: #cbd8e6;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QPushButton {
|
||||
color: #e0e0e0;
|
||||
text-align: center;
|
||||
min-width: 70px;
|
||||
background-color: #2a2a2a; /* Middle Mouse Navigation Button and Ok Cancel Apply Help Preferences Buttons */
|
||||
border: 2px solid #2a2a2a;
|
||||
border-bottom-color: #1e1e1e; /* simulates shadow under the button */
|
||||
padding: 2px 2px;
|
||||
margin: 2px 2px;
|
||||
min-height: 16px; /* same as QTabBar QPushButton min-width */
|
||||
background-color: #2a2a2a;
|
||||
padding: 4px 20px;
|
||||
border: 1px solid #494949;
|
||||
margin: 4px 4px;
|
||||
border-radius: 1px;
|
||||
|
||||
}
|
||||
|
||||
QPushButton:hover,
|
||||
QPushButton:focus {
|
||||
color: #cbd8e6;
|
||||
border: -2px solid #333333;
|
||||
background-color: #557BB6;
|
||||
color: #ffffff;
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QPushButton:disabled,
|
||||
QPushButton:disabled:checked {
|
||||
color: #f5f5f5;
|
||||
background-color: #2a2a2a; /* same as enabled color */
|
||||
border-color: #2a2a2a; /* same as enabled color */
|
||||
border: 1px solid #2a2a2a; /* same as enabled color */
|
||||
}
|
||||
|
||||
QPushButton:pressed {
|
||||
background-color: #557BB6;
|
||||
color: #ffffff;
|
||||
background-color: #48699a;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
QPushButton:checked {
|
||||
background-color: #557BB6;
|
||||
border: solid #557BB6;
|
||||
border: 1px solid #557BB6;
|
||||
}
|
||||
|
||||
/* Inspect Widgets Addon */
|
||||
|
||||
QDockWidget#InspectWidgets QPushButton {
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #3c3c3c;
|
||||
min-height: 16px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
QDockWidget#InspectWidgets QPushButton:hover {
|
||||
color: #ffffff;
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #f5f5f5;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QDockWidget#InspectWidgets QPushButton:checked,
|
||||
QDockWidget#InspectWidgets QPushButton:pressed {
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #557bb6;
|
||||
}
|
||||
|
||||
/* CAD Navigation Style */
|
||||
|
||||
QPushButton#NavigationIndicator {
|
||||
background-color: #557bb6;
|
||||
padding: 2px;
|
||||
margin: 0px;
|
||||
border: 1px solid #333333;
|
||||
border-radius: 1px;
|
||||
min-width: 90px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
QPushButton:hover#NavigationIndicator {
|
||||
color: #ffffff;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QPushButton:pressed#NavigationIndicator {
|
||||
color: #ffffff;
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #557bb6;
|
||||
}
|
||||
|
||||
/* BIM Views Manager */
|
||||
|
||||
QWidget#Form QPushButton {
|
||||
background-color: #333333;
|
||||
padding: 4px 2px;
|
||||
border: 1px solid #3c3c3c;
|
||||
border-radius: 1px;
|
||||
margin: 2px;
|
||||
margin-bottom: 8px;
|
||||
max-width: 100%;
|
||||
min-width: 16px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
QWidget#Form QPushButton:hover {
|
||||
border: 1px solid #f5f5f5;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QWidget#Form QPushButton:pressed {
|
||||
border: 1px solid #557bb6;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
/* Sketcher Manual Update Button */
|
||||
|
||||
QPushButton#manualUpdate {
|
||||
padding: 4px;
|
||||
margin: 0px;
|
||||
border: 1px solid #494949;
|
||||
}
|
||||
|
||||
QPushButton:pressed#manualUpdate {
|
||||
color: #ffffff;
|
||||
border: 1px solid #3c3c3c;
|
||||
background-color: #48699a;
|
||||
}
|
||||
|
||||
/* Addon Manager */
|
||||
|
||||
QDialog#Dialog QPushButton {
|
||||
padding: 4px;
|
||||
margin: 0px;
|
||||
border: 1px solid #494949;
|
||||
}
|
||||
|
||||
QDialog#Dialog QPushButton:hover {
|
||||
color: #ffffff;
|
||||
border: 1px solid #3c3c3c;
|
||||
background-color: #48699a;
|
||||
}
|
||||
|
||||
QPushButton#buttonUninstall {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
QPushButton#buttonClose {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* Ok Cancel Apply Help Preferences Buttons */ /* Hack to move Help button left */
|
||||
|
||||
QDialogButtonBox > QPushButton {
|
||||
color: #e0e0e0;
|
||||
text-align: center;
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #494949;
|
||||
padding: 4px;
|
||||
margin-right: 8px;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
/* Color Buttons */
|
||||
@@ -1644,7 +1696,7 @@ Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QPushButton {
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #1e1e1e;
|
||||
min-width: 16px; /* reset it due to larger value on regular QPushButton, same or bigger value as regular QPushButton min-height */
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 0px; /* reset */
|
||||
padding: 0px; /* reset */
|
||||
}
|
||||
@@ -1653,48 +1705,44 @@ Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QPushButton {
|
||||
Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QWidget > QWidget > QFrame {
|
||||
background-color: #333333; /* main background color */
|
||||
border: 1px solid #333333;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
QPushButton:checked {
|
||||
background-color: #3c3c3c;
|
||||
border-color: #3c3c3c;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Customize -> Macros -> Pixmap "..." button */
|
||||
|
||||
QDialog QToolButton {
|
||||
color: #e0e0e0;
|
||||
text-align: center;
|
||||
background-color: qlineargradient(spread:pad, x1:0, y1:0.3, x2:0, y2:1, stop:0 #2a2a2a, stop:1 #1e1e1e);
|
||||
border: 1px solid #1e1e1e;
|
||||
border-bottom-color: black; /* simulates shadow under the button */
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #494949;
|
||||
padding: 0px; /* different than regular QPushButton */
|
||||
margin: 2px; /* different than regular QPushButton */
|
||||
margin: 2px;
|
||||
min-height: 16px; /* same as QTabBar QPushButton min-width */
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QDialog QToolButton:hover,
|
||||
QDialog QToolButton:focus {
|
||||
color: #cbd8e6;
|
||||
border-color: #557BB6;
|
||||
background-color: #557BB6;
|
||||
color: #ffffff;
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QDialog QToolButton:disabled,
|
||||
QDialog QToolButton:disabled:checked {
|
||||
color: #333333;
|
||||
border-color: #424242;
|
||||
background-color: #424242;
|
||||
color: #f5f5f5;
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #2a2a2a;
|
||||
}
|
||||
|
||||
QDialog QToolButton:pressed {
|
||||
background-color: #557BB6;
|
||||
color: #ffffff;
|
||||
background-color: #48699a;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
|
||||
@@ -1711,7 +1759,7 @@ QSint--ActionGroup QFrame[class="content"] QToolButton {
|
||||
padding: 2px 6px; /* different than regular QPushButton */
|
||||
margin: 2px; /* different than regular QPushButton */
|
||||
min-height: 16px; /* same as QTabBar QPushButton min-width */
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QSint--ActionGroup QFrame[class="content"] QToolButton:hover,
|
||||
@@ -1779,7 +1827,7 @@ QRadioButton:disabled {
|
||||
QRadioButton::indicator {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:pressed {
|
||||
@@ -1944,7 +1992,7 @@ QSlider:vertical {
|
||||
QSlider::groove {
|
||||
background-color: #2a2a2a;
|
||||
border: 2px solid #3c3c3c;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 4px 0px;
|
||||
}
|
||||
|
||||
@@ -1968,7 +2016,7 @@ QSlider::handle:vertical {
|
||||
border: 1px solid #2a2a2a;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
@@ -2028,35 +2076,44 @@ QToolBar > QPushButton {
|
||||
margin: 0px; /* doesn't work with :left, :right:, :top or :bottom sub-controls */
|
||||
min-width: 24px; /* could not be larger due to switchable Preferences "Size of toolbar icons" */
|
||||
min-height: 24px; /* could not be larger due to switchable Preferences "Size of toolbar icons" */
|
||||
border-radius: 2px; /* same as regular QPushButton */
|
||||
border-radius: 1px; /* same as regular QPushButton */
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:checked {
|
||||
border: 1px solid #333333;
|
||||
border: 1px solid #3c3c3c;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
/* Hack to avoid QPushButton text partially hidden under menu-indicator */
|
||||
QToolBar > QPushButton::menu-indicator:!checked {
|
||||
image: none;
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:!checked {
|
||||
background-color: #333333; /* Current Working Plane and Nudge */
|
||||
border: 1px solid #333333;
|
||||
text-align: left;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #3c3c3c;
|
||||
margin: 0px 2px;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:checked:hover {
|
||||
border-color: #557BB6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:!checked:hover {
|
||||
color: #ffffff;
|
||||
background-color: #557BB6;
|
||||
border-color: #557BB6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:checked:pressed {
|
||||
border: 1px solid #557bb6;
|
||||
background-color: solid #557BB6;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:!checked:pressed {
|
||||
border: 1px solid #557bb6;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
@@ -2069,43 +2126,60 @@ QToolBar > QPushButton:!checked:disabled {
|
||||
QToolBar > QToolButton {
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton:hover {
|
||||
background-color: #557BB6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton:pressed {
|
||||
background-color: #557BB6;
|
||||
border: 1px solid #557bb6;
|
||||
}
|
||||
|
||||
/* ToolBar menu buttons (buttons with drop-down menu) */
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton {
|
||||
padding-right: 20px; /* Hack to add more width to buttons with menu */
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:hover,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:pressed,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:open {
|
||||
border: 1px solid #557BB6;
|
||||
border: 1px solid #333333;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QToolBar QToolButton::menu-button,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button {
|
||||
border: none;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-top-right-radius: 1px;
|
||||
border-bottom-right-radius: 1px;
|
||||
width: 16px; /* 16px width + 4px for border = 20px allocated above */
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button:hover,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button:hover {
|
||||
border-top: 1px solid #f5f5f5;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
border-right: 1px solid #f5f5f5;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:pressed,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:open {
|
||||
background-color: #557BB6;
|
||||
border: 1px solid #557BB6;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:hover {
|
||||
background-color: #557BB6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button:pressed,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button:open {
|
||||
border-top: 1px solid #557bb6;
|
||||
border-bottom: 1px solid #557bb6;
|
||||
border-right: 1px solid #557bb6;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
@@ -2208,7 +2282,7 @@ QTableView > QWidget > QTimeEdit:down-button,
|
||||
QTableView > QWidget > QDateEdit:down-button,
|
||||
QTableView > QWidget > QDateTimeEdit:down-button,
|
||||
QTableView > QWidget > Gui--ColorButton {
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QTableView > QWidget > QComboBox,
|
||||
@@ -2334,7 +2408,7 @@ QToolBar#Selector QToolButton {
|
||||
border: none;
|
||||
margin: 0px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
/* Active tab */
|
||||
|
||||
@@ -204,6 +204,10 @@ class _TaskPanel:
|
||||
# leave task panel ***************************************************************************
|
||||
def accept(self):
|
||||
# print(self.material)
|
||||
if self.material == {}: # happens if material editor was canceled
|
||||
FreeCAD.Console.PrintError("Empty material dictionary, nothing was changed.\n")
|
||||
self.recompute_and_set_back_all()
|
||||
return True
|
||||
if self.selectionWidget.has_equal_references_shape_types():
|
||||
self.do_not_set_thermal_zeros()
|
||||
from materialtools.cardutils import check_mat_units as checkunits
|
||||
|
||||
@@ -82,6 +82,8 @@
|
||||
|
||||
#include "ImpExpDxf.h"
|
||||
|
||||
namespace Import {
|
||||
|
||||
class ImportOCAFExt : public Import::ImportOCAF2
|
||||
{
|
||||
public:
|
||||
@@ -98,7 +100,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
namespace Import {
|
||||
class Module : public Py::ExtensionModule<Module>
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <Base/Console.h>
|
||||
#include <Base/FileInfo.h>
|
||||
#include <Base/Parameter.h>
|
||||
#include <Base/Stream.h>
|
||||
#include <Base/Vector3D.h>
|
||||
#include "dxf.h"
|
||||
|
||||
@@ -47,7 +48,8 @@ m_layerName("none")
|
||||
// start the file
|
||||
m_fail = false;
|
||||
m_version = 12;
|
||||
m_ofs = new ofstream(filepath, ios::out);
|
||||
Base::FileInfo fi(filepath);
|
||||
m_ofs = new Base::ofstream(fi, ios::out);
|
||||
m_ssBlock = new std::ostringstream();
|
||||
m_ssBlkRecord = new std::ostringstream();
|
||||
m_ssEntity = new std::ostringstream();
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
|
||||
FC_LOG_LEVEL_INIT("Import", true, true)
|
||||
|
||||
namespace ImportGui {
|
||||
class OCAFBrowser
|
||||
{
|
||||
public:
|
||||
@@ -382,7 +383,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace ImportGui {
|
||||
class Module : public Py::ExtensionModule<Module>
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -44,6 +44,8 @@ SOURCE_GROUP("MatLib" FILES ${MaterialLib_Files})
|
||||
SET (FluidMaterial_Files
|
||||
FluidMaterial/None.FCMat
|
||||
FluidMaterial/Air.FCMat
|
||||
FluidMaterial/Argon.FCMat
|
||||
FluidMaterial/Nitrogen.FCMat
|
||||
FluidMaterial/Water.FCMat
|
||||
FluidMaterial/Readme.md
|
||||
)
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
[General]
|
||||
Name = Air
|
||||
Description = Standard air properties at 20 Degrees Celsius and 1 atm
|
||||
Description = Dry air properties at 20 Degrees Celsius and 1 atm
|
||||
MolarMass = 28.965
|
||||
Father = Gas
|
||||
|
||||
[Fluidic]
|
||||
Density = 1.20 kg/m^3
|
||||
Density = 1.204 kg/m^3
|
||||
DynamicViscosity = 1.80e-5 kg/m/s
|
||||
KinematicViscosity = 1.511e-5 m^2/s
|
||||
; PrandtlNumber is a nondimension number for CFD simulation
|
||||
PrandtlNumber = 0.7
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 1.005 J/kg/K
|
||||
ThermalConductivity = 0.0257 W/m/K
|
||||
SpecificHeat = 1.01 kJ/kg/K
|
||||
ThermalConductivity = 0.02587 W/m/K
|
||||
; volumetric expansion coeff of ideal gas depends on temperature and pressure
|
||||
VolumetricThermalExpansionCoefficient = 3.43e-3 m/m/K
|
||||
|
||||
[Electrical]
|
||||
RelativePermittivity = 1.00059
|
||||
; at 18°C and 50Hz
|
||||
ElectricalConductivity = 1e-12 S/m
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
[General]
|
||||
Name = Argon
|
||||
Description = Argon properties at 20 Degrees Celsius and 1 atm
|
||||
MolarMass = 39.95
|
||||
Father = Gas
|
||||
|
||||
[Fluidic]
|
||||
Density = 1.641 kg/m^3
|
||||
DynamicViscosity = 22.3e-6 kg/m/s
|
||||
; Kinematic Viscosity = Dynamic Viscosity / Density
|
||||
KinematicViscosity = 13.59-6 m^2/s
|
||||
; PrandtlNumber is a nondimension number for CFD simulation
|
||||
PrandtlNumber = 0.7
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 0.520 kJ/kg/K
|
||||
ThermalConductivity = 0.018 W/m/K
|
||||
; volumetric expansion coeff of ideal gas depends on temperature and pressure
|
||||
VolumetricThermalExpansionCoefficient = 3.43e-3 1/K
|
||||
|
||||
[Electrical]
|
||||
RelativePermittivity = 1.000513
|
||||
ElectricalConductivity = 1e-15 S/m
|
||||
@@ -0,0 +1,23 @@
|
||||
[General]
|
||||
Name = Nitrogen
|
||||
Description = Nitrogen properties at 20 Degrees Celsius and 1 atm
|
||||
MolarMass = 14.007
|
||||
Father = Gas
|
||||
|
||||
[Fluidic]
|
||||
Density = 1.2506 kg/m^3
|
||||
DynamicViscosity = 17.58e-6 kg/m/s
|
||||
; Kinematic Viscosity = Dynamic Viscosity / Density
|
||||
KinematicViscosity = 14.06e-6 m^2/s
|
||||
; PrandtlNumber is a nondimension number for CFD simulation
|
||||
PrandtlNumber = 0.7
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 1.04 kJ/kg/K
|
||||
ThermalConductivity = 25.83e−3 W/m/K
|
||||
; volumetric expansion coeff of ideal gas depends on temperature and pressure
|
||||
VolumetricThermalExpansionCoefficient = 3.43e-3 1/K
|
||||
|
||||
[Electrical]
|
||||
RelativePermittivity = 1.00058
|
||||
ElectricalConductivity = 1e-12 S/m
|
||||
@@ -22,3 +22,4 @@ VolumetricThermalExpansionCoefficient = 2.07e-4 m/m/K
|
||||
[Electrical]
|
||||
RelativePermittivity = 80.0
|
||||
; at 20°C and 50Hz
|
||||
ElectricalConductivity = 5.5e-6 S/m
|
||||
|
||||
+11
-145
@@ -52,6 +52,7 @@
|
||||
|
||||
#include "Mesh.h"
|
||||
#include "Exporter.h"
|
||||
#include "Importer.h"
|
||||
#include "FeatureMeshImport.h"
|
||||
#include <Mod/Mesh/App/MeshPy.h>
|
||||
|
||||
@@ -173,79 +174,11 @@ private:
|
||||
std::string EncodedName = std::string(Name);
|
||||
PyMem_Free(Name);
|
||||
|
||||
MeshObject mesh;
|
||||
MeshCore::Material mat;
|
||||
if (mesh.load(EncodedName.c_str(), &mat)) {
|
||||
Base::FileInfo file(EncodedName.c_str());
|
||||
// create new document and add Import feature
|
||||
App::Document *pcDoc = App::GetApplication().newDocument("Unnamed");
|
||||
unsigned long segmct = mesh.countSegments();
|
||||
if (segmct > 1) {
|
||||
for (unsigned long i=0; i<segmct; i++) {
|
||||
const Segment& group = mesh.getSegment(i);
|
||||
std::string groupName = group.getName();
|
||||
if (groupName.empty())
|
||||
groupName = file.fileNamePure();
|
||||
// create new document and add Import feature
|
||||
App::Document *pcDoc = App::GetApplication().newDocument("Unnamed");
|
||||
|
||||
std::unique_ptr<MeshObject> segm(mesh.meshFromSegment(group.getIndices()));
|
||||
Mesh::Feature *pcFeature = static_cast<Mesh::Feature *>
|
||||
(pcDoc->addObject("Mesh::Feature", groupName.c_str()));
|
||||
pcFeature->Label.setValue(groupName.c_str());
|
||||
pcFeature->Mesh.swapMesh(*segm);
|
||||
|
||||
// if colors are set per face
|
||||
if (mat.binding == MeshCore::MeshIO::PER_FACE &&
|
||||
mat.diffuseColor.size() == mesh.countFacets()) {
|
||||
App::PropertyColorList* prop = static_cast<App::PropertyColorList*>
|
||||
(pcFeature->addDynamicProperty("App::PropertyColorList", "VertexColors"));
|
||||
if (prop) {
|
||||
std::vector<App::Color> diffuseColor;
|
||||
diffuseColor.reserve(group.getIndices().size());
|
||||
for (const auto& it : group.getIndices()) {
|
||||
diffuseColor.push_back(mat.diffuseColor[it]);
|
||||
}
|
||||
prop->setValues(diffuseColor);
|
||||
}
|
||||
}
|
||||
pcFeature->purgeTouched();
|
||||
}
|
||||
}
|
||||
else if (mat.binding == MeshCore::MeshIO::PER_VERTEX &&
|
||||
mat.diffuseColor.size() == mesh.countPoints()) {
|
||||
FeatureCustom *pcFeature = new FeatureCustom();
|
||||
pcFeature->Label.setValue(file.fileNamePure().c_str());
|
||||
pcFeature->Mesh.swapMesh(mesh);
|
||||
App::PropertyColorList* prop = static_cast<App::PropertyColorList*>
|
||||
(pcFeature->addDynamicProperty("App::PropertyColorList", "VertexColors"));
|
||||
if (prop) {
|
||||
prop->setValues(mat.diffuseColor);
|
||||
}
|
||||
pcFeature->purgeTouched();
|
||||
|
||||
pcDoc->addObject(pcFeature, file.fileNamePure().c_str());
|
||||
}
|
||||
else if (mat.binding == MeshCore::MeshIO::PER_FACE &&
|
||||
mat.diffuseColor.size() == mesh.countFacets()) {
|
||||
FeatureCustom *pcFeature = new FeatureCustom();
|
||||
pcFeature->Label.setValue(file.fileNamePure().c_str());
|
||||
pcFeature->Mesh.swapMesh(mesh);
|
||||
App::PropertyColorList* prop = static_cast<App::PropertyColorList*>
|
||||
(pcFeature->addDynamicProperty("App::PropertyColorList", "FaceColors"));
|
||||
if (prop) {
|
||||
prop->setValues(mat.diffuseColor);
|
||||
}
|
||||
pcFeature->purgeTouched();
|
||||
|
||||
pcDoc->addObject(pcFeature, file.fileNamePure().c_str());
|
||||
}
|
||||
else {
|
||||
Mesh::Feature *pcFeature = static_cast<Mesh::Feature *>
|
||||
(pcDoc->addObject("Mesh::Feature", file.fileNamePure().c_str()));
|
||||
pcFeature->Label.setValue(file.fileNamePure().c_str());
|
||||
pcFeature->Mesh.swapMesh(mesh);
|
||||
pcFeature->purgeTouched();
|
||||
}
|
||||
}
|
||||
Mesh::Importer import(pcDoc);
|
||||
import.load(EncodedName);
|
||||
|
||||
return Py::None();
|
||||
}
|
||||
@@ -260,86 +193,19 @@ private:
|
||||
PyMem_Free(Name);
|
||||
|
||||
App::Document *pcDoc = 0;
|
||||
if (DocName)
|
||||
if (DocName) {
|
||||
pcDoc = App::GetApplication().getDocument(DocName);
|
||||
else
|
||||
}
|
||||
else {
|
||||
pcDoc = App::GetApplication().getActiveDocument();
|
||||
}
|
||||
|
||||
if (!pcDoc) {
|
||||
pcDoc = App::GetApplication().newDocument(DocName);
|
||||
}
|
||||
|
||||
MeshObject mesh;
|
||||
MeshCore::Material mat;
|
||||
if (mesh.load(EncodedName.c_str(), &mat)) {
|
||||
Base::FileInfo file(EncodedName.c_str());
|
||||
unsigned long segmct = mesh.countSegments();
|
||||
if (segmct > 1) {
|
||||
for (unsigned long i=0; i<segmct; i++) {
|
||||
const Segment& group = mesh.getSegment(i);
|
||||
std::string groupName = group.getName();
|
||||
if (groupName.empty())
|
||||
groupName = file.fileNamePure();
|
||||
|
||||
std::unique_ptr<MeshObject> segm(mesh.meshFromSegment(group.getIndices()));
|
||||
Mesh::Feature *pcFeature = static_cast<Mesh::Feature *>
|
||||
(pcDoc->addObject("Mesh::Feature", groupName.c_str()));
|
||||
pcFeature->Label.setValue(groupName.c_str());
|
||||
pcFeature->Mesh.swapMesh(*segm);
|
||||
|
||||
// if colors are set per face
|
||||
if (mat.binding == MeshCore::MeshIO::PER_FACE &&
|
||||
mat.diffuseColor.size() == mesh.countFacets()) {
|
||||
App::PropertyColorList* prop = static_cast<App::PropertyColorList*>
|
||||
(pcFeature->addDynamicProperty("App::PropertyColorList", "VertexColors"));
|
||||
if (prop) {
|
||||
std::vector<App::Color> diffuseColor;
|
||||
diffuseColor.reserve(group.getIndices().size());
|
||||
for (const auto& it : group.getIndices()) {
|
||||
diffuseColor.push_back(mat.diffuseColor[it]);
|
||||
}
|
||||
prop->setValues(diffuseColor);
|
||||
}
|
||||
}
|
||||
pcFeature->purgeTouched();
|
||||
}
|
||||
}
|
||||
else if (mat.binding == MeshCore::MeshIO::PER_VERTEX &&
|
||||
mat.diffuseColor.size() == mesh.countPoints()) {
|
||||
FeatureCustom *pcFeature = new FeatureCustom();
|
||||
pcFeature->Label.setValue(file.fileNamePure().c_str());
|
||||
pcFeature->Mesh.swapMesh(mesh);
|
||||
App::PropertyColorList* prop = static_cast<App::PropertyColorList*>
|
||||
(pcFeature->addDynamicProperty("App::PropertyColorList", "VertexColors"));
|
||||
if (prop) {
|
||||
prop->setValues(mat.diffuseColor);
|
||||
}
|
||||
pcFeature->purgeTouched();
|
||||
|
||||
pcDoc->addObject(pcFeature, file.fileNamePure().c_str());
|
||||
}
|
||||
else if (mat.binding == MeshCore::MeshIO::PER_FACE &&
|
||||
mat.diffuseColor.size() == mesh.countFacets()) {
|
||||
FeatureCustom *pcFeature = new FeatureCustom();
|
||||
pcFeature->Label.setValue(file.fileNamePure().c_str());
|
||||
pcFeature->Mesh.swapMesh(mesh);
|
||||
App::PropertyColorList* prop = static_cast<App::PropertyColorList*>
|
||||
(pcFeature->addDynamicProperty("App::PropertyColorList", "FaceColors"));
|
||||
if (prop) {
|
||||
prop->setValues(mat.diffuseColor);
|
||||
}
|
||||
pcFeature->purgeTouched();
|
||||
|
||||
pcDoc->addObject(pcFeature, file.fileNamePure().c_str());
|
||||
}
|
||||
else {
|
||||
Mesh::Feature *pcFeature = static_cast<Mesh::Feature *>
|
||||
(pcDoc->addObject("Mesh::Feature", file.fileNamePure().c_str()));
|
||||
pcFeature->Label.setValue(file.fileNamePure().c_str());
|
||||
pcFeature->Mesh.swapMesh(mesh);
|
||||
pcFeature->purgeTouched();
|
||||
}
|
||||
}
|
||||
Mesh::Importer import(pcDoc);
|
||||
import.load(EncodedName);
|
||||
|
||||
return Py::None();
|
||||
}
|
||||
|
||||
@@ -329,6 +329,8 @@ SET(Mesh_SRCS
|
||||
AppMeshPy.cpp
|
||||
Exporter.cpp
|
||||
Exporter.h
|
||||
Importer.cpp
|
||||
Importer.h
|
||||
Facet.cpp
|
||||
Facet.h
|
||||
FacetPyImp.cpp
|
||||
|
||||
@@ -341,11 +341,6 @@ bool MeshInput::LoadOBJ (std::istream &rstrIn)
|
||||
unsigned long countMaterialFacets = 0;
|
||||
|
||||
while (std::getline(rstrIn, line)) {
|
||||
// when a group name comes don't make it lower case
|
||||
if (!line.empty() && line[0] != 'g') {
|
||||
for (std::string::iterator it = line.begin(); it != line.end(); ++it)
|
||||
*it = tolower(*it);
|
||||
}
|
||||
if (boost::regex_match(line.c_str(), what, rx_p)) {
|
||||
fX = (float)std::atof(what[1].first);
|
||||
fY = (float)std::atof(what[4].first);
|
||||
@@ -1285,8 +1280,7 @@ bool MeshInput::LoadMeshNode (std::istream &rstrIn)
|
||||
return false;
|
||||
|
||||
while (std::getline(rstrIn, line)) {
|
||||
for (std::string::iterator it = line.begin(); it != line.end(); ++it)
|
||||
*it = tolower(*it);
|
||||
boost::algorithm::to_lower(line);
|
||||
if (boost::regex_match(line.c_str(), what, rx_p)) {
|
||||
fX = (float)std::atof(what[1].first);
|
||||
fY = (float)std::atof(what[4].first);
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2021 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include "Importer.h"
|
||||
#include "MeshFeature.h"
|
||||
#include <App/Document.h>
|
||||
|
||||
using namespace Mesh;
|
||||
|
||||
|
||||
Importer::Importer(App::Document* doc)
|
||||
: document(doc)
|
||||
{
|
||||
}
|
||||
|
||||
void Importer::load(const std::string& fileName)
|
||||
{
|
||||
MeshObject mesh;
|
||||
MeshCore::Material mat;
|
||||
|
||||
if (mesh.load(fileName.c_str(), &mat)) {
|
||||
Base::FileInfo file(fileName.c_str());
|
||||
unsigned long segmct = mesh.countSegments();
|
||||
if (segmct > 1) {
|
||||
createMeshFromSegments(file.fileNamePure(), mat, mesh);
|
||||
}
|
||||
else if (mat.binding == MeshCore::MeshIO::PER_VERTEX &&
|
||||
mat.diffuseColor.size() == mesh.countPoints()) {
|
||||
Feature* feature = createMesh(file.fileNamePure(), mesh);
|
||||
addVertexColors(feature, mat.diffuseColor);
|
||||
feature->purgeTouched();
|
||||
}
|
||||
else if (mat.binding == MeshCore::MeshIO::PER_FACE &&
|
||||
mat.diffuseColor.size() == mesh.countFacets()) {
|
||||
Feature* feature = createMesh(file.fileNamePure(), mesh);
|
||||
addFaceColors(feature, mat.diffuseColor);
|
||||
feature->purgeTouched();
|
||||
}
|
||||
else {
|
||||
Feature* feature = createMesh(file.fileNamePure(), mesh);
|
||||
feature->purgeTouched();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Importer::addVertexColors(Feature* feature, const std::vector<App::Color>& colors)
|
||||
{
|
||||
addColors(feature, "VertexColors", colors);
|
||||
}
|
||||
|
||||
void Importer::addFaceColors(Feature* feature, const std::vector<App::Color>& colors)
|
||||
{
|
||||
addColors(feature, "FaceColors", colors);
|
||||
}
|
||||
|
||||
void Importer::addColors(Feature* feature, const std::string& property, const std::vector<App::Color>& colors)
|
||||
{
|
||||
App::PropertyColorList* prop = static_cast<App::PropertyColorList*>
|
||||
(feature->addDynamicProperty("App::PropertyColorList", property.c_str()));
|
||||
if (prop) {
|
||||
prop->setValues(colors);
|
||||
}
|
||||
}
|
||||
|
||||
void Importer::createMeshFromSegments(const std::string& name, MeshCore::Material& mat, MeshObject& mesh)
|
||||
{
|
||||
unsigned long segmct = mesh.countSegments();
|
||||
for (unsigned long i=0; i<segmct; i++) {
|
||||
const Segment& group = mesh.getSegment(i);
|
||||
std::string groupName = group.getName();
|
||||
if (groupName.empty())
|
||||
groupName = name;
|
||||
|
||||
std::unique_ptr<MeshObject> segm(mesh.meshFromSegment(group.getIndices()));
|
||||
Feature* feature = createMesh(groupName, *segm);
|
||||
|
||||
// if colors are set per face
|
||||
if (mat.binding == MeshCore::MeshIO::PER_FACE &&
|
||||
mat.diffuseColor.size() == mesh.countFacets()) {
|
||||
|
||||
std::vector<App::Color> diffuseColor;
|
||||
diffuseColor.reserve(group.getIndices().size());
|
||||
for (const auto& it : group.getIndices()) {
|
||||
diffuseColor.push_back(mat.diffuseColor[it]);
|
||||
}
|
||||
|
||||
addFaceColors(feature, diffuseColor);
|
||||
}
|
||||
feature->purgeTouched();
|
||||
}
|
||||
}
|
||||
|
||||
Feature* Importer::createMesh(const std::string& name, MeshObject& mesh)
|
||||
{
|
||||
Mesh::Feature *pcFeature = static_cast<Mesh::Feature *>
|
||||
(document->addObject("Mesh::Feature", name.c_str()));
|
||||
pcFeature->Label.setValue(name);
|
||||
pcFeature->Mesh.swapMesh(mesh);
|
||||
return pcFeature;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2021 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MESH_IMPORTER_H
|
||||
#define MESH_IMPORTER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace App {
|
||||
class Document;
|
||||
class Color;
|
||||
}
|
||||
|
||||
namespace MeshCore {
|
||||
struct Material;
|
||||
}
|
||||
namespace Mesh
|
||||
{
|
||||
class MeshObject;
|
||||
class Feature;
|
||||
|
||||
class Importer
|
||||
{
|
||||
public:
|
||||
Importer(App::Document*);
|
||||
~Importer() = default;
|
||||
|
||||
void load(const std::string& fileName);
|
||||
|
||||
private:
|
||||
void addVertexColors(Feature*, const std::vector<App::Color>&);
|
||||
void addFaceColors(Feature*, const std::vector<App::Color>&);
|
||||
void addColors(Feature*, const std::string& property, const std::vector<App::Color>&);
|
||||
Feature* createMesh(const std::string& name, MeshObject&);
|
||||
void createMeshFromSegments(const std::string& name, MeshCore::Material& mat, MeshObject& mesh);
|
||||
|
||||
private:
|
||||
App::Document* document;
|
||||
};
|
||||
|
||||
} // namespace Mesh
|
||||
|
||||
#endif // MESH_IMPORTER_H
|
||||
@@ -1539,6 +1539,37 @@ bool GeomBSplineCurve::removeKnot(int index, int multiplicity, double tolerance)
|
||||
}
|
||||
}
|
||||
|
||||
void GeomBSplineCurve::Trim(double u, double v)
|
||||
{
|
||||
auto splitUnwrappedBSpline = [this](double u, double v) {
|
||||
// it makes a copy internally (checked in the source code of OCCT)
|
||||
auto handle = GeomConvert::SplitBSplineCurve ( myCurve,
|
||||
u,
|
||||
v,
|
||||
Precision::Confusion()
|
||||
);
|
||||
setHandle(handle);
|
||||
};
|
||||
|
||||
try {
|
||||
if(!isPeriodic()) {
|
||||
splitUnwrappedBSpline(u, v);
|
||||
}
|
||||
else { // periodic
|
||||
if( v < u ) { // wraps over origin
|
||||
v = v + 1.0; // v needs one extra lap (1.0)
|
||||
|
||||
splitUnwrappedBSpline(u, v);
|
||||
}
|
||||
else {
|
||||
splitUnwrappedBSpline(u, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
THROWM(Base::CADKernelError,e.GetMessageString())
|
||||
}
|
||||
}
|
||||
|
||||
// Persistence implementer
|
||||
unsigned int GeomBSplineCurve::getMemSize (void) const
|
||||
|
||||
@@ -307,6 +307,8 @@ public:
|
||||
void increaseMultiplicity(int index, int multiplicity);
|
||||
bool removeKnot(int index, int multiplicity, double tolerance = Precision::PConfusion());
|
||||
|
||||
void Trim(double u, double v);
|
||||
|
||||
// Persistence implementer ---------------------
|
||||
virtual unsigned int getMemSize(void) const;
|
||||
virtual void Save(Base::Writer &/*writer*/) const;
|
||||
|
||||
@@ -108,11 +108,11 @@ Base::Axis Part2DObject::getAxis(int axId) const
|
||||
}
|
||||
|
||||
bool Part2DObject::seekTrimPoints(const std::vector<Geometry *> &geomlist,
|
||||
int GeoId, const Base::Vector3d &point,
|
||||
int &GeoId1, Base::Vector3d &intersect1,
|
||||
int &GeoId2, Base::Vector3d &intersect2)
|
||||
int geometryIndex, const Base::Vector3d &point,
|
||||
int &geometryIndex1, Base::Vector3d &intersect1,
|
||||
int &geometryIndex2, Base::Vector3d &intersect2)
|
||||
{
|
||||
if (GeoId >= int(geomlist.size()))
|
||||
if ( geometryIndex >= int(geomlist.size()))
|
||||
return false;
|
||||
|
||||
gp_Pln plane(gp_Pnt(0,0,0),gp_Dir(0,0,1));
|
||||
@@ -120,7 +120,7 @@ bool Part2DObject::seekTrimPoints(const std::vector<Geometry *> &geomlist,
|
||||
Standard_Boolean periodic=Standard_False;
|
||||
double period = 0;
|
||||
Handle(Geom2d_Curve) primaryCurve;
|
||||
Handle(Geom_Geometry) geom = (geomlist[GeoId])->handle();
|
||||
Handle(Geom_Geometry) geom = (geomlist[geometryIndex])->handle();
|
||||
Handle(Geom_Curve) curve3d = Handle(Geom_Curve)::DownCast(geom);
|
||||
|
||||
if (curve3d.IsNull())
|
||||
@@ -141,14 +141,14 @@ bool Part2DObject::seekTrimPoints(const std::vector<Geometry *> &geomlist,
|
||||
double pickedParam = Projector.LowerDistanceParameter();
|
||||
|
||||
// find intersection points
|
||||
GeoId1 = -1;
|
||||
GeoId2 = -1;
|
||||
geometryIndex1 = -1;
|
||||
geometryIndex2 = -1;
|
||||
double param1=-1e10,param2=1e10;
|
||||
gp_Pnt2d p1,p2;
|
||||
Handle(Geom2d_Curve) secondaryCurve;
|
||||
for (int id=0; id < int(geomlist.size()); id++) {
|
||||
// #0000624: Trim tool doesn't work with construction lines
|
||||
if (id != GeoId/* && !geomlist[id]->Construction*/) {
|
||||
if (id != geometryIndex/* && !geomlist[id]->Construction*/) {
|
||||
geom = (geomlist[id])->handle();
|
||||
curve3d = Handle(Geom_Curve)::DownCast(geom);
|
||||
if (!curve3d.IsNull()) {
|
||||
@@ -205,24 +205,24 @@ bool Part2DObject::seekTrimPoints(const std::vector<Geometry *> &geomlist,
|
||||
if (param > param1) {
|
||||
param1 = param;
|
||||
p1 = p;
|
||||
GeoId1 = id;
|
||||
geometryIndex1 = id;
|
||||
}
|
||||
param -= period; // transfer param into the interval (pickedParam pickedParam+period]
|
||||
if (param < param2) {
|
||||
param2 = param;
|
||||
p2 = p;
|
||||
GeoId2 = id;
|
||||
geometryIndex2 = id;
|
||||
}
|
||||
}
|
||||
else if (param < pickedParam && param > param1) {
|
||||
param1 = param;
|
||||
p1 = p;
|
||||
GeoId1 = id;
|
||||
geometryIndex1 = id;
|
||||
}
|
||||
else if (param > pickedParam && param < param2) {
|
||||
param2 = param;
|
||||
p2 = p;
|
||||
GeoId2 = id;
|
||||
geometryIndex2 = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,18 +233,18 @@ bool Part2DObject::seekTrimPoints(const std::vector<Geometry *> &geomlist,
|
||||
// in case both points coincide, cancel the selection of one of both
|
||||
if (fabs(param2-param1-period) < 1e-10) {
|
||||
if (param2 - pickedParam >= pickedParam - param1)
|
||||
GeoId2 = -1;
|
||||
geometryIndex2 = -1;
|
||||
else
|
||||
GeoId1 = -1;
|
||||
geometryIndex1 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (GeoId1 < 0 && GeoId2 < 0)
|
||||
if ( geometryIndex1 < 0 && geometryIndex2 < 0)
|
||||
return false;
|
||||
|
||||
if (GeoId1 >= 0)
|
||||
if ( geometryIndex1 >= 0)
|
||||
intersect1 = Base::Vector3d(p1.X(),p1.Y(),0.f);
|
||||
if (GeoId2 >= 0)
|
||||
if ( geometryIndex2 >= 0)
|
||||
intersect2 = Base::Vector3d(p2.X(),p2.Y(),0.f);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -66,17 +66,19 @@ public:
|
||||
/// verify and accept the assigned geometry
|
||||
virtual void acceptGeometry();
|
||||
|
||||
/** calculate the points where a curve with index GeoId should be trimmed
|
||||
/** calculate the points where a curve with index geometryIndex should be trimmed
|
||||
* with respect to the rest of the curves contained in the list geomlist
|
||||
* and a picked point. The outputs intersect1 and intersect2 specify the
|
||||
* tightest boundaries for trimming around the picked point and the
|
||||
* indexes GeoId1 and GeoId2 specify the corresponding curves that intersect
|
||||
* the curve GeoId.
|
||||
* indexes geometryIndex1 and geometryIndex2 specify the corresponding curves that intersect
|
||||
* the curve geometryIndex.
|
||||
*
|
||||
* If intersection is found, the associated geometryIndex1 or geometryIndex2 retuns -1.
|
||||
*/
|
||||
static bool seekTrimPoints(const std::vector<Geometry *> &geomlist,
|
||||
int GeoId, const Base::Vector3d &point,
|
||||
int &GeoId1, Base::Vector3d &intersect1,
|
||||
int &GeoId2, Base::Vector3d &intersect2);
|
||||
int geometryIndex, const Base::Vector3d &point,
|
||||
int &geometryIndex1, Base::Vector3d &intersect1,
|
||||
int &geometryIndex2, Base::Vector3d &intersect2);
|
||||
|
||||
static const int H_Axis;
|
||||
static const int V_Axis;
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
using namespace PartDesign;
|
||||
|
||||
const char* Pad::TypeEnums[]= {"Length","UpToLast","UpToFirst","UpToFace","TwoLengths",NULL};
|
||||
const char* Pad::TypeEnums[]= {"Length", "UpToLast", "UpToFirst", "UpToFace", "TwoLengths", NULL};
|
||||
|
||||
PROPERTY_SOURCE(PartDesign::Pad, PartDesign::ProfileBased)
|
||||
|
||||
@@ -70,6 +70,7 @@ Pad::Pad()
|
||||
ADD_PROPERTY_TYPE(Length2, (100.0), "Pad", App::Prop_None,"Second Pad length");
|
||||
ADD_PROPERTY_TYPE(UseCustomVector, (0), "Pad", App::Prop_None, "Use custom vector for pad direction");
|
||||
ADD_PROPERTY_TYPE(Direction, (Base::Vector3d(1.0, 1.0, 1.0)), "Pad", App::Prop_None, "Pad direction vector");
|
||||
ADD_PROPERTY_TYPE(AlongCustomVector, (true), "Pad", App::Prop_None, "Measure length along custom direction vector");
|
||||
ADD_PROPERTY_TYPE(UpToFace, (0), "Pad", App::Prop_None, "Face where pad will end");
|
||||
ADD_PROPERTY_TYPE(Offset, (0.0), "Pad", App::Prop_None, "Offset from face in which pad will end");
|
||||
static const App::PropertyQuantityConstraint::Constraints signedLengthConstraint = {-DBL_MAX, DBL_MAX, 1.0};
|
||||
@@ -88,6 +89,7 @@ short Pad::mustExecute() const
|
||||
Length2.isTouched() ||
|
||||
UseCustomVector.isTouched() ||
|
||||
Direction.isTouched() ||
|
||||
AlongCustomVector.isTouched() ||
|
||||
Offset.isTouched() ||
|
||||
UpToFace.isTouched())
|
||||
return 1;
|
||||
@@ -104,6 +106,12 @@ App::DocumentObjectExecReturn *Pad::execute(void)
|
||||
if ((std::string(Type.getValueAsString()) == "TwoLengths") && (L < Precision::Confusion()))
|
||||
return new App::DocumentObjectExecReturn("Second length of pad too small");
|
||||
|
||||
// if midplane is true, disable reversed and vice versa
|
||||
bool hasMidplane = Midplane.getValue();
|
||||
bool hasReversed = Reversed.getValue();
|
||||
Midplane.setReadOnly(hasReversed);
|
||||
Reversed.setReadOnly(hasMidplane);
|
||||
|
||||
Part::Feature* obj = 0;
|
||||
TopoDS_Shape sketchshape;
|
||||
try {
|
||||
@@ -133,12 +141,13 @@ App::DocumentObjectExecReturn *Pad::execute(void)
|
||||
base.Move(invObjLoc);
|
||||
|
||||
Base::Vector3d paddingDirection;
|
||||
|
||||
// use the given vector if necessary
|
||||
|
||||
if (!UseCustomVector.getValue()) {
|
||||
// use sketch's normal vector for direction
|
||||
paddingDirection = SketchVector;
|
||||
}
|
||||
else {
|
||||
// use the given vector
|
||||
// if null vector, use SketchVector
|
||||
if ( (fabs(Direction.getValue().x) < Precision::Confusion())
|
||||
&& (fabs(Direction.getValue().y) < Precision::Confusion())
|
||||
@@ -168,9 +177,15 @@ App::DocumentObjectExecReturn *Pad::execute(void)
|
||||
if (factor < Precision::Confusion())
|
||||
return new App::DocumentObjectExecReturn("Pad: Creation failed because direction is orthogonal to sketch's normal vector");
|
||||
|
||||
// perform the length correction
|
||||
L = L / factor;
|
||||
L2 = L2 / factor;
|
||||
// perform the length correction if not along custom vector
|
||||
if (AlongCustomVector.getValue()) {
|
||||
L = L / factor;
|
||||
L2 = L2 / factor;
|
||||
}
|
||||
|
||||
// explicitly set the Direction so that the dialog shows also the used direction
|
||||
// if the sketch's normal vector was used
|
||||
Direction.setValue(paddingDirection);
|
||||
|
||||
dir.Transform(invObjLoc.Transformation());
|
||||
|
||||
@@ -306,7 +321,7 @@ App::DocumentObjectExecReturn *Pad::execute(void)
|
||||
}
|
||||
} else {
|
||||
generatePrism(prism, sketchshape, method, dir, L, L2,
|
||||
Midplane.getValue(), Reversed.getValue());
|
||||
hasMidplane, hasReversed);
|
||||
}
|
||||
|
||||
if (prism.IsNull())
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
App::PropertyLength Length2;
|
||||
App::PropertyBool UseCustomVector;
|
||||
App::PropertyVector Direction;
|
||||
App::PropertyBool AlongCustomVector;
|
||||
App::PropertyLength Offset;
|
||||
|
||||
/** @name methods override feature */
|
||||
|
||||
@@ -587,8 +587,13 @@ void ProfileBased::generatePrism(TopoDS_Shape& prism,
|
||||
|
||||
if (method == "TwoLengths") {
|
||||
// midplane makes no sense here
|
||||
Loffset = -L2;
|
||||
Ltotal += L2;
|
||||
if (reversed)
|
||||
Loffset = -L;
|
||||
else if (midplane)
|
||||
Loffset = -0.5 * (L2 + L);
|
||||
else
|
||||
Loffset = -L2;
|
||||
} else if (midplane)
|
||||
Loffset = -Ltotal/2;
|
||||
|
||||
|
||||
@@ -34,15 +34,15 @@
|
||||
#include "TaskPadParameters.h"
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/UnitsApi.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Document.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/Document.h>
|
||||
#include <Gui/Selection.h>
|
||||
#include <Gui/ViewProvider.h>
|
||||
#include <Gui/WaitCursor.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Gui/Selection.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Mod/PartDesign/App/FeaturePad.h>
|
||||
#include <Mod/Sketcher/App/SketchObject.h>
|
||||
#include "TaskSketchBasedParameters.h"
|
||||
@@ -75,6 +75,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView, QWidget *parent,
|
||||
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
|
||||
Base::Quantity l = pcPad->Length.getQuantityValue();
|
||||
Base::Quantity l2 = pcPad->Length2.getQuantityValue();
|
||||
bool alongCustom = pcPad->AlongCustomVector.getValue();
|
||||
bool useCustom = pcPad->UseCustomVector.getValue();
|
||||
double xs = pcPad->Direction.getValue().x;
|
||||
double ys = pcPad->Direction.getValue().y;
|
||||
@@ -93,10 +94,18 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView, QWidget *parent,
|
||||
faceId = std::atoi(&upToFace[4]);
|
||||
}
|
||||
|
||||
// set decimals for the direction edits
|
||||
// do this here before the edits are filed to avoid rounding mistakes
|
||||
int UserDecimals = Base::UnitsApi::getDecimals();
|
||||
ui->XDirectionEdit->setDecimals(UserDecimals);
|
||||
ui->YDirectionEdit->setDecimals(UserDecimals);
|
||||
ui->ZDirectionEdit->setDecimals(UserDecimals);
|
||||
|
||||
// Fill data into dialog elements
|
||||
ui->lengthEdit->setValue(l);
|
||||
ui->lengthEdit2->setValue(l2);
|
||||
ui->groupBoxDirection->setChecked(useCustom);
|
||||
ui->checkBoxAlongDirection->setChecked(alongCustom);
|
||||
ui->XDirectionEdit->setValue(xs);
|
||||
ui->YDirectionEdit->setValue(ys);
|
||||
ui->ZDirectionEdit->setValue(zs);
|
||||
@@ -105,23 +114,16 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView, QWidget *parent,
|
||||
// Bind input fields to properties
|
||||
ui->lengthEdit->bind(pcPad->Length);
|
||||
ui->lengthEdit2->bind(pcPad->Length2);
|
||||
|
||||
ui->XDirectionEdit->bind(App::ObjectIdentifier::parse(pcPad, std::string("Direction.x")));
|
||||
ui->YDirectionEdit->bind(App::ObjectIdentifier::parse(pcPad, std::string("Direction.y")));
|
||||
ui->ZDirectionEdit->bind(App::ObjectIdentifier::parse(pcPad, std::string("Direction.z")));
|
||||
|
||||
ui->offsetEdit->bind(pcPad->Offset);
|
||||
|
||||
ui->checkBoxMidplane->setChecked(midplane);
|
||||
// According to bug #0000521 the reversed option
|
||||
// shouldn't be de-activated if the pad has a support face
|
||||
ui->checkBoxReversed->setChecked(reversed);
|
||||
|
||||
// set decimals for the direction edits
|
||||
int UserDecimals = Base::UnitsApi::getDecimals();
|
||||
ui->XDirectionEdit->setDecimals(UserDecimals);
|
||||
ui->YDirectionEdit->setDecimals(UserDecimals);
|
||||
ui->ZDirectionEdit->setDecimals(UserDecimals);
|
||||
|
||||
// Set object labels
|
||||
if (obj && PartDesign::Feature::isDatum(obj)) {
|
||||
ui->lineFaceName->setText(QString::fromUtf8(obj->Label.getValue()));
|
||||
@@ -138,7 +140,6 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView, QWidget *parent,
|
||||
ui->lineFaceName->clear();
|
||||
ui->lineFaceName->setProperty("FeatureName", QVariant());
|
||||
}
|
||||
|
||||
ui->lineFaceName->setProperty("FaceName", QByteArray(upToFace.c_str()));
|
||||
|
||||
ui->changeMode->clear();
|
||||
@@ -155,8 +156,10 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView, QWidget *parent,
|
||||
this, SLOT(onLengthChanged(double)));
|
||||
connect(ui->lengthEdit2, SIGNAL(valueChanged(double)),
|
||||
this, SLOT(onLength2Changed(double)));
|
||||
connect(ui->checkBoxAlongDirection, SIGNAL(toggled(bool)),
|
||||
this, SLOT(onAlongDirectionChanged(bool)));
|
||||
connect(ui->groupBoxDirection, SIGNAL(toggled(bool)),
|
||||
this, SLOT(onGBDirectionChanged(bool)));
|
||||
this, SLOT(onDirectionToggled(bool)));
|
||||
connect(ui->XDirectionEdit, SIGNAL(valueChanged(double)),
|
||||
this, SLOT(onXDirectionEditChanged(double)));
|
||||
connect(ui->YDirectionEdit, SIGNAL(valueChanged(double)),
|
||||
@@ -197,34 +200,35 @@ void TaskPadParameters::updateUI(int index)
|
||||
{
|
||||
// disable/hide everything unless we are sure we don't need it
|
||||
// exception: the direction parameters are in any case visible
|
||||
bool isLengthEditVisable = false;
|
||||
bool isLengthEdit2Visable = false;
|
||||
bool isOffsetEditVisable = false;
|
||||
bool isLengthEditVisible = false;
|
||||
bool isLengthEdit2Visible = false;
|
||||
bool isOffsetEditVisible = false;
|
||||
bool isMidplateEnabled = false;
|
||||
bool isReversedEnabled = false;
|
||||
bool isReversedVisible = false;
|
||||
bool isFaceEditEnabled = false;
|
||||
|
||||
// dimension
|
||||
if (index == 0) {
|
||||
isLengthEditVisable = true;
|
||||
isLengthEditVisible = true;
|
||||
ui->lengthEdit->selectNumber();
|
||||
// Make sure that the spin box has the focus to get key events
|
||||
// Calling setFocus() directly doesn't work because the spin box is not
|
||||
// yet visible.
|
||||
QMetaObject::invokeMethod(ui->lengthEdit, "setFocus", Qt::QueuedConnection);
|
||||
isMidplateEnabled = true;
|
||||
isMidplateEnabled = !ui->checkBoxReversed->isChecked();
|
||||
// Reverse only makes sense if Midplane is not true
|
||||
isReversedEnabled = !ui->checkBoxMidplane->isChecked();
|
||||
isReversedVisible = true;
|
||||
}
|
||||
// up to first/last
|
||||
else if (index == 1 || index == 2) {
|
||||
isOffsetEditVisable = true;
|
||||
isReversedEnabled = true;
|
||||
isOffsetEditVisible = true;
|
||||
}
|
||||
// up to face
|
||||
else if (index == 3) {
|
||||
isOffsetEditVisable = true;
|
||||
isFaceEditEnabled = true;
|
||||
isOffsetEditVisible = true;
|
||||
isFaceEditEnabled = true;
|
||||
QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection);
|
||||
// Go into reference selection mode if no face has been selected yet
|
||||
if (ui->lineFaceName->property("FeatureName").isNull())
|
||||
@@ -232,25 +236,30 @@ void TaskPadParameters::updateUI(int index)
|
||||
}
|
||||
// two dimensions
|
||||
else {
|
||||
isLengthEditVisable = true;
|
||||
isLengthEdit2Visable = true;
|
||||
isLengthEditVisible = true;
|
||||
isLengthEdit2Visible = true;
|
||||
isMidplateEnabled = !ui->checkBoxReversed->isChecked();
|
||||
isReversedEnabled = !ui->checkBoxMidplane->isChecked();
|
||||
isReversedVisible = true;
|
||||
}
|
||||
|
||||
ui->lengthEdit->setVisible( isLengthEditVisable );
|
||||
ui->lengthEdit->setEnabled( isLengthEditVisable );
|
||||
ui->labelLength->setVisible( isLengthEditVisable );
|
||||
ui->lengthEdit->setVisible( isLengthEditVisible );
|
||||
ui->lengthEdit->setEnabled( isLengthEditVisible );
|
||||
ui->labelLength->setVisible( isLengthEditVisible );
|
||||
ui->checkBoxAlongDirection->setVisible( isLengthEditVisible );
|
||||
|
||||
ui->offsetEdit->setVisible( isOffsetEditVisable );
|
||||
ui->offsetEdit->setEnabled( isOffsetEditVisable );
|
||||
ui->labelOffset->setVisible( isOffsetEditVisable );
|
||||
ui->offsetEdit->setVisible( isOffsetEditVisible );
|
||||
ui->offsetEdit->setEnabled( isOffsetEditVisible );
|
||||
ui->labelOffset->setVisible( isOffsetEditVisible );
|
||||
|
||||
ui->checkBoxMidplane->setEnabled( isMidplateEnabled );
|
||||
|
||||
ui->checkBoxReversed->setEnabled( isReversedEnabled );
|
||||
ui->checkBoxReversed->setVisible( isReversedVisible );
|
||||
|
||||
ui->lengthEdit2->setVisible( isLengthEdit2Visable );
|
||||
ui->lengthEdit2->setEnabled( isLengthEdit2Visable );
|
||||
ui->labelLength2->setVisible( isLengthEdit2Visable );
|
||||
ui->lengthEdit2->setVisible( isLengthEdit2Visible );
|
||||
ui->lengthEdit2->setEnabled( isLengthEdit2Visible );
|
||||
ui->labelLength2->setVisible( isLengthEdit2Visible );
|
||||
|
||||
ui->buttonFace->setEnabled( isFaceEditEnabled );
|
||||
ui->lineFaceName->setEnabled( isFaceEditEnabled );
|
||||
@@ -301,11 +310,26 @@ void TaskPadParameters::onLength2Changed(double len)
|
||||
recomputeFeature();
|
||||
}
|
||||
|
||||
void TaskPadParameters::onGBDirectionChanged(bool on)
|
||||
void TaskPadParameters::onAlongDirectionChanged(bool on)
|
||||
{
|
||||
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
|
||||
pcPad->AlongCustomVector.setValue(on);
|
||||
recomputeFeature();
|
||||
}
|
||||
|
||||
void TaskPadParameters::onDirectionToggled(bool on)
|
||||
{
|
||||
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
|
||||
pcPad->UseCustomVector.setValue(on);
|
||||
// dis/enable length direction
|
||||
ui->checkBoxAlongDirection->setEnabled(on);
|
||||
if (!on)
|
||||
ui->checkBoxAlongDirection->setChecked(!on);
|
||||
recomputeFeature();
|
||||
// the calculation of the sketch's normal vector is done in FeaturePad.cpp
|
||||
// if this vector was used for the recomputation we must fill the direction
|
||||
// vector edit fields. Therefore update
|
||||
updateDirectionEdits();
|
||||
}
|
||||
|
||||
void TaskPadParameters::onXDirectionEditChanged(double len)
|
||||
@@ -319,7 +343,6 @@ void TaskPadParameters::onXDirectionEditChanged(double len)
|
||||
updateDirectionEdits();
|
||||
}
|
||||
|
||||
|
||||
void TaskPadParameters::onYDirectionEditChanged(double len)
|
||||
{
|
||||
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
|
||||
@@ -339,9 +362,16 @@ void TaskPadParameters::onZDirectionEditChanged(double len)
|
||||
void TaskPadParameters::updateDirectionEdits(void)
|
||||
{
|
||||
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
|
||||
// we don't want to execute the onChanged edits, but just update their contents
|
||||
ui->XDirectionEdit->blockSignals(true);
|
||||
ui->YDirectionEdit->blockSignals(true);
|
||||
ui->ZDirectionEdit->blockSignals(true);
|
||||
ui->XDirectionEdit->setValue(pcPad->Direction.getValue().x);
|
||||
ui->YDirectionEdit->setValue(pcPad->Direction.getValue().y);
|
||||
ui->ZDirectionEdit->setValue(pcPad->Direction.getValue().z);
|
||||
ui->XDirectionEdit->blockSignals(false);
|
||||
ui->YDirectionEdit->blockSignals(false);
|
||||
ui->ZDirectionEdit->blockSignals(false);
|
||||
}
|
||||
|
||||
void TaskPadParameters::onOffsetChanged(double len)
|
||||
@@ -355,6 +385,7 @@ void TaskPadParameters::onMidplaneChanged(bool on)
|
||||
{
|
||||
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
|
||||
pcPad->Midplane.setValue(on);
|
||||
// reversed is not sensible when midplane
|
||||
ui->checkBoxReversed->setEnabled(!on);
|
||||
recomputeFeature();
|
||||
}
|
||||
@@ -363,6 +394,8 @@ void TaskPadParameters::onReversedChanged(bool on)
|
||||
{
|
||||
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
|
||||
pcPad->Reversed.setValue(on);
|
||||
// midplane is not sensible when reversed
|
||||
ui->checkBoxMidplane->setEnabled(!on);
|
||||
recomputeFeature();
|
||||
}
|
||||
|
||||
@@ -391,6 +424,7 @@ void TaskPadParameters::onButtonFace(const bool pressed)
|
||||
{
|
||||
this->blockConnection(!pressed);
|
||||
|
||||
// only faces are allowed
|
||||
TaskSketchBasedParameters::onSelectReference(pressed, false, true, false);
|
||||
|
||||
// Update button if onButtonFace() is called explicitly
|
||||
@@ -432,6 +466,11 @@ double TaskPadParameters::getLength2(void) const
|
||||
return ui->lengthEdit2->value().getValue();
|
||||
}
|
||||
|
||||
bool TaskPadParameters::getAlongCustom(void) const
|
||||
{
|
||||
return ui->checkBoxAlongDirection->isChecked();
|
||||
}
|
||||
|
||||
bool TaskPadParameters::getCustom(void) const
|
||||
{
|
||||
return ui->groupBoxDirection->isChecked();
|
||||
@@ -563,6 +602,7 @@ void TaskPadParameters::apply()
|
||||
FCMD_OBJ_CMD(obj, "UseCustomVector = " << (getCustom() ? 1 : 0));
|
||||
FCMD_OBJ_CMD(obj, "Direction = ("
|
||||
<< getXDirection() << ", " << getYDirection() << ", " << getZDirection() << ")");
|
||||
FCMD_OBJ_CMD(obj, "AlongCustomVector = " << (getAlongCustom() ? 1 : 0));
|
||||
FCMD_OBJ_CMD(obj,"Type = " << getMode());
|
||||
QString facename = getFaceName();
|
||||
FCMD_OBJ_CMD(obj,"UpToFace = " << facename.toLatin1().data());
|
||||
|
||||
@@ -58,7 +58,8 @@ public:
|
||||
private Q_SLOTS:
|
||||
void onLengthChanged(double);
|
||||
void onLength2Changed(double);
|
||||
void onGBDirectionChanged(bool);
|
||||
void onAlongDirectionChanged(bool);
|
||||
void onDirectionToggled(bool);
|
||||
void onXDirectionEditChanged(double);
|
||||
void onYDirectionEditChanged(double);
|
||||
void onZDirectionEditChanged(double);
|
||||
@@ -75,6 +76,7 @@ protected:
|
||||
private:
|
||||
double getLength(void) const;
|
||||
double getLength2(void) const;
|
||||
bool getAlongCustom(void) const;
|
||||
bool getCustom(void) const;
|
||||
double getXDirection(void) const;
|
||||
double getYDirection(void) const;
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>280</width>
|
||||
<height>350</height>
|
||||
<height>373</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
@@ -66,97 +66,114 @@ the sketch plane's normal vector will be used</string>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelXSkew">
|
||||
<property name="text">
|
||||
<string>x</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::DoubleSpinBox" name="XDirectionEdit">
|
||||
<property name="toolTip">
|
||||
<string>x-component of direction vector</string>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelYSkew">
|
||||
<property name="text">
|
||||
<string>y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::DoubleSpinBox" name="YDirectionEdit">
|
||||
<property name="toolTip">
|
||||
<string>y-component of direction vector</string>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelZSkew">
|
||||
<property name="text">
|
||||
<string>z</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::DoubleSpinBox" name="ZDirectionEdit">
|
||||
<property name="toolTip">
|
||||
<string>z-component of direction vector</string>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelXSkew">
|
||||
<property name="text">
|
||||
<string>x</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::DoubleSpinBox" name="XDirectionEdit">
|
||||
<property name="toolTip">
|
||||
<string>x-component of direction vector</string>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelYSkew">
|
||||
<property name="text">
|
||||
<string>y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::DoubleSpinBox" name="YDirectionEdit">
|
||||
<property name="toolTip">
|
||||
<string>y-component of direction vector</string>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelZSkew">
|
||||
<property name="text">
|
||||
<string>z</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::DoubleSpinBox" name="ZDirectionEdit">
|
||||
<property name="toolTip">
|
||||
<string>z-component of direction vector</string>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBoxAlongDirection">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>If unchecked, the length will be
|
||||
measured along the specified direction</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Length along sketch normal</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -159,8 +159,8 @@ class TestPad(unittest.TestCase):
|
||||
self.Body.addObject(self.Pad1)
|
||||
self.Pad1.Profile = self.PadSketch1
|
||||
self.Pad1.Type = 4
|
||||
self.Pad1.Length = 2.0
|
||||
self.Pad1.Length2 = 1.0
|
||||
self.Pad1.Length = 1.0
|
||||
self.Pad1.Length2 = 2.0
|
||||
self.Pad1.Reversed = 1
|
||||
self.Doc.recompute()
|
||||
self.assertAlmostEqual(self.Pad1.Shape.Volume, 4.0)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -140,8 +140,17 @@ public:
|
||||
int addCopyOfConstraints(const SketchObject &orig);
|
||||
/// add constraint
|
||||
int addConstraint(const Constraint *constraint);
|
||||
/// add constraint
|
||||
int addConstraint(std::unique_ptr<Constraint> constraint);
|
||||
/// delete constraint
|
||||
int delConstraint(int ConstrId);
|
||||
/** deletes a group of constraints at once, if norecomputes is active, the default behaviour is that
|
||||
* it will solve the sketch.
|
||||
*
|
||||
* If updating the Geometry property as a consequence of a (sucessful) solve() is not wanted, updategeometry=false,
|
||||
* prevents the update. This allows to update the solve status (e.g. dof), without updating the geometry (i.e. make it
|
||||
* move to fulfil the constraints).
|
||||
*/
|
||||
int delConstraints(std::vector<int> ConstrIds, bool updategeometry=true);
|
||||
int delConstraintOnPoint(int GeoId, PointPos PosId, bool onlyCoincident=true);
|
||||
int delConstraintOnPoint(int VertexId, bool onlyCoincident=true);
|
||||
@@ -168,7 +177,12 @@ public:
|
||||
* id==-2 for the vertical sketch axis
|
||||
* id<=-3 for user defined projected external geometries,
|
||||
*/
|
||||
const Part::Geometry* getGeometry(int GeoId) const;
|
||||
template < typename GeometryT = Part::Geometry,
|
||||
typename = typename std::enable_if<
|
||||
std::is_base_of<Part::Geometry, typename std::decay<GeometryT>::type>::value
|
||||
>::type
|
||||
>
|
||||
const GeometryT * getGeometry(int GeoId) const;
|
||||
|
||||
std::unique_ptr<const GeometryFacade> getGeometryFacade(int GeoId) const;
|
||||
|
||||
@@ -184,6 +198,11 @@ public:
|
||||
/// retrieves a vector containing both normal and external Geometry (including the sketch axes)
|
||||
std::vector<Part::Geometry*> getCompleteGeometry(void) const;
|
||||
|
||||
/// converts a GeoId index into an index of the CompleteGeometry vector
|
||||
int getCompleteGeometryIndex(int GeoId) const;
|
||||
|
||||
int getGeoIdFromCompleteGeometryIndex(int completeGeometryIndex) const;
|
||||
|
||||
/// returns non zero if the sketch contains conflicting constraints
|
||||
int hasConflicts(void) const;
|
||||
/**
|
||||
@@ -458,6 +477,14 @@ public:
|
||||
bool isCarbonCopyAllowed(App::Document *pDoc, App::DocumentObject *pObj, bool & xinv, bool & yinv, eReasonList* rsn = 0) const;
|
||||
|
||||
bool isPerformingInternalTransaction() const {return internaltransaction;};
|
||||
|
||||
/** retrieves intersection points of this curve with the closest two curves around a point of this curve.
|
||||
* - it includes internal and external intersecting geometry.
|
||||
* - it returns Constraint::GeoUndef if no intersection is found.
|
||||
*/
|
||||
bool seekTrimPoints(int GeoId, const Base::Vector3d &point,
|
||||
int &GeoId1, Base::Vector3d &intersect1,
|
||||
int &GeoId2, Base::Vector3d &intersect2);
|
||||
public:
|
||||
// Analyser functions
|
||||
int autoConstraint(double precision = Precision::Confusion() * 1000, double angleprecision = M_PI/20, bool includeconstruction = true);
|
||||
@@ -556,6 +583,24 @@ protected:
|
||||
// and corrects the state if not matching.
|
||||
void synchroniseGeometryState();
|
||||
|
||||
// helper function to create a new constraint and move it to the Constraint Property
|
||||
void addConstraint( Sketcher::ConstraintType constrType,
|
||||
int firstGeoId,
|
||||
Sketcher::PointPos firstPos,
|
||||
int secondGeoId = Constraint::GeoUndef,
|
||||
Sketcher::PointPos secondPos = Sketcher::none,
|
||||
int thirdGeoId = Constraint::GeoUndef,
|
||||
Sketcher::PointPos thirdPos = Sketcher::none);
|
||||
|
||||
// creates a new constraint
|
||||
std::unique_ptr<Constraint> createConstraint( Sketcher::ConstraintType constrType,
|
||||
int firstGeoId,
|
||||
Sketcher::PointPos firstPos,
|
||||
int secondGeoId = Constraint::GeoUndef,
|
||||
Sketcher::PointPos secondPos = Sketcher::none,
|
||||
int thirdGeoId = Constraint::GeoUndef,
|
||||
Sketcher::PointPos thirdPos = Sketcher::none);
|
||||
|
||||
private:
|
||||
/// Flag to allow external geometry from other bodies than the one this sketch belongs to
|
||||
bool allowOtherBody;
|
||||
@@ -631,6 +676,21 @@ inline int SketchObject::moveTemporaryPoint(int geoId, PointPos pos, Base::Vecto
|
||||
return solvedSketch.movePoint(geoId, pos, toPoint, relative);
|
||||
}
|
||||
|
||||
template < typename GeometryT,
|
||||
typename >
|
||||
const GeometryT * SketchObject::getGeometry(int GeoId) const
|
||||
{
|
||||
if (GeoId >= 0) {
|
||||
const std::vector<Part::Geometry *> &geomlist = getInternalGeometry();
|
||||
if (GeoId < int(geomlist.size()))
|
||||
return static_cast<GeometryT *>(geomlist[GeoId]);
|
||||
}
|
||||
else if (-GeoId <= int(ExternalGeo.size()))
|
||||
return static_cast<GeometryT *>(ExternalGeo[-GeoId-1]);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
typedef App::FeaturePythonT<SketchObject> SketchObjectPython;
|
||||
|
||||
} //namespace Sketcher
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <Gui/DlgEditFileIncludePropertyExternal.h>
|
||||
#include <Gui/Action.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
#include <Gui/DlgCheckableMessageBox.h>
|
||||
|
||||
#include <Mod/Part/App/Geometry.h>
|
||||
#include <Mod/Sketcher/App/SketchObject.h>
|
||||
@@ -641,9 +642,9 @@ bool SketcherGui::checkConstraint(const std::vector< Sketcher::Constraint * > &v
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void SketcherGui::doEndpointTangency(Sketcher::SketchObject* Obj, Gui::SelectionObject &selection,
|
||||
int GeoId1, int GeoId2, PointPos PosId1, PointPos PosId2){
|
||||
void SketcherGui::doEndpointTangency(Sketcher::SketchObject* Obj,
|
||||
int GeoId1, int GeoId2, PointPos PosId1, PointPos PosId2)
|
||||
{
|
||||
// This code supports simple B-spline endpoint tangency to any other geometric curve
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
|
||||
@@ -659,10 +660,27 @@ void SketcherGui::doEndpointTangency(Sketcher::SketchObject* Obj, Gui::Selection
|
||||
// GeoId1 is the B-spline now
|
||||
} // end of code supports simple B-spline endpoint tangency
|
||||
|
||||
Gui::cmdAppObjectArgs(selection.getObject(), "addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d,%d)) ",
|
||||
Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d,%d)) ",
|
||||
GeoId1,PosId1,GeoId2,PosId2);
|
||||
}
|
||||
|
||||
void SketcherGui::doEndpointToEdgeTangency( Sketcher::SketchObject* Obj, int GeoId1, PointPos PosId1, int GeoId2)
|
||||
{
|
||||
Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d)) ",
|
||||
GeoId1,PosId1,GeoId2);
|
||||
}
|
||||
|
||||
void SketcherGui::notifyConstraintSubstitutions(const QString & message)
|
||||
{
|
||||
Gui::Dialog::DlgCheckableMessageBox::showMessage( QObject::tr("Sketcher Constraint Substitution"),
|
||||
message,
|
||||
QLatin1String("User parameter:BaseApp/Preferences/Mod/Sketcher/General"),
|
||||
QLatin1String("NotifyConstraintSubstitutions"),
|
||||
true, // Default ParamEntry
|
||||
true, // checkbox state
|
||||
QObject::tr("Keep notifying me of constraint substitutions"));
|
||||
}
|
||||
|
||||
|
||||
namespace SketcherGui {
|
||||
|
||||
@@ -2054,6 +2072,10 @@ public:
|
||||
protected:
|
||||
virtual void activated(int iMsg);
|
||||
virtual void applyConstraint(std::vector<SelIdPair> &selSeq, int seqIndex);
|
||||
// returns true if a substitution took place
|
||||
bool substituteConstraintCombinations(SketchObject * Obj,
|
||||
int GeoId1, PointPos PosId1,
|
||||
int GeoId2, PointPos PosId2);
|
||||
};
|
||||
|
||||
CmdSketcherConstrainCoincident::CmdSketcherConstrainCoincident()
|
||||
@@ -2072,6 +2094,48 @@ CmdSketcherConstrainCoincident::CmdSketcherConstrainCoincident()
|
||||
allowedSelSequences = {{SelVertex, SelVertexOrRoot}, {SelRoot, SelVertex}};
|
||||
}
|
||||
|
||||
bool CmdSketcherConstrainCoincident::substituteConstraintCombinations(SketchObject * Obj,
|
||||
int GeoId1, PointPos PosId1,
|
||||
int GeoId2, PointPos PosId2)
|
||||
{
|
||||
// checks for direct and indirect coincidence constraints
|
||||
bool constraintExists = Obj->arePointsCoincident(GeoId1,PosId1,GeoId2,PosId2);
|
||||
|
||||
const std::vector< Constraint * > &cvals = Obj->Constraints.getValues();
|
||||
|
||||
int j=0;
|
||||
for (std::vector<Constraint *>::const_iterator it = cvals.begin(); it != cvals.end(); ++it,++j) {
|
||||
if( (*it)->Type == Sketcher::Tangent &&
|
||||
(*it)->FirstPos == Sketcher::none && (*it)->SecondPos == Sketcher::none &&
|
||||
(*it)->Third == Constraint::GeoUndef &&
|
||||
(((*it)->First == GeoId1 && (*it)->Second == GeoId2) ||
|
||||
((*it)->Second == GeoId1 && (*it)->First == GeoId2)) ) {
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Swap edge tangency with ptp tangency"));
|
||||
|
||||
if( constraintExists ) {
|
||||
// try to remove any pre-existing direct coincident constraints
|
||||
Gui::cmdAppObjectArgs(Obj, "delConstraintOnPoint(%i,%i)", GeoId1, PosId1);
|
||||
}
|
||||
|
||||
Gui::cmdAppObjectArgs(Obj, "delConstraint(%i)", j);
|
||||
|
||||
doEndpointTangency(Obj, GeoId1, GeoId2, PosId1, PosId2);
|
||||
|
||||
commitCommand();
|
||||
Obj->solve(); // The substitution requires a solve() so that the autoremove redundants works when Autorecompute not active.
|
||||
tryAutoRecomputeIfNotSolve(Obj);
|
||||
|
||||
notifyConstraintSubstitutions(QObject::tr("Endpoint to endpoint tangency was applied instead."));
|
||||
|
||||
getSelection().clearSelection();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CmdSketcherConstrainCoincident::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
@@ -2133,47 +2197,16 @@ void CmdSketcherConstrainCoincident::activated(int iMsg)
|
||||
return;
|
||||
}
|
||||
|
||||
// check if as a consequence of this command undesirable combinations of constraints would
|
||||
// arise and substitute them with more appropriate counterparts, examples:
|
||||
// - coincidence + tangency on edge
|
||||
// - point on object + tangency on edge
|
||||
if(substituteConstraintCombinations(Obj, GeoId1, PosId1,GeoId2, PosId2))
|
||||
return;
|
||||
|
||||
// check if this coincidence is already enforced (even indirectly)
|
||||
bool constraintExists=Obj->arePointsCoincident(GeoId1,PosId1,GeoId2,PosId2);
|
||||
|
||||
// check for a preexisting edge-to-edge tangency
|
||||
const std::vector< Constraint * > &cvals = Obj->Constraints.getValues();
|
||||
|
||||
int j=0;
|
||||
for (std::vector<Constraint *>::const_iterator it = cvals.begin(); it != cvals.end(); ++it,++j) {
|
||||
if( (*it)->Type == Sketcher::Tangent &&
|
||||
(*it)->FirstPos == Sketcher::none && (*it)->SecondPos == Sketcher::none &&
|
||||
(*it)->Third == Constraint::GeoUndef &&
|
||||
(((*it)->First == GeoId1 && (*it)->Second == GeoId2) ||
|
||||
((*it)->Second == GeoId1 && (*it)->First == GeoId2)) ) {
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Swap edge tangency with ptp tangency"));
|
||||
|
||||
if(constraintExists) {
|
||||
// try to remove any pre-existing direct coincident constraints
|
||||
Gui::cmdAppObjectArgs(Obj, "delConstraintOnPoint(%i,%i)", GeoId1, PosId1);
|
||||
}
|
||||
|
||||
Gui::cmdAppObjectArgs(Obj, "delConstraint(%i)", j);
|
||||
|
||||
doEndpointTangency(Obj, selection[0], GeoId1, GeoId2, PosId1, PosId2);
|
||||
|
||||
commitCommand();
|
||||
Obj->solve(); // The substitution requires a solve() so that the autoremove redundants works when Autorecompute not active.
|
||||
tryAutoRecomputeIfNotSolve(Obj);
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
|
||||
if(hGrp->GetBool("NotifyConstraintSubstitutions", true)) {
|
||||
QMessageBox::information(Gui::getMainWindow(), QObject::tr("Constraint Substitution"),
|
||||
QObject::tr("Endpoint to endpoint tangency was applied instead."));
|
||||
}
|
||||
|
||||
getSelection().clearSelection();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!constraintExists) {
|
||||
constraintsAdded = true;
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ",
|
||||
@@ -2211,6 +2244,13 @@ void CmdSketcherConstrainCoincident::applyConstraint(std::vector<SelIdPair> &sel
|
||||
return;
|
||||
}
|
||||
|
||||
// check if as a consequence of this command undesirable combinations of constraints would
|
||||
// arise and substitute them with more appropriate counterparts, examples:
|
||||
// - coincidence + tangency on edge
|
||||
// - point on object + tangency on edge
|
||||
if(substituteConstraintCombinations(Obj, GeoId1, PosId1,GeoId2, PosId2))
|
||||
return;
|
||||
|
||||
// undo command open
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add coincident constraint"));
|
||||
|
||||
@@ -2588,10 +2628,11 @@ public:
|
||||
protected:
|
||||
virtual void activated(int iMsg);
|
||||
virtual void applyConstraint(std::vector<SelIdPair> &selSeq, int seqIndex);
|
||||
// returns true if a substitution took place
|
||||
bool substituteConstraintCombinations(SketchObject * Obj,
|
||||
int GeoId1, PointPos PosId1, int GeoId2);
|
||||
};
|
||||
|
||||
//DEF_STD_CMD_A(CmdSketcherConstrainPointOnObject);
|
||||
|
||||
CmdSketcherConstrainPointOnObject::CmdSketcherConstrainPointOnObject()
|
||||
:CmdSketcherConstraint("Sketcher_ConstrainPointOnObject")
|
||||
{
|
||||
@@ -2612,6 +2653,36 @@ CmdSketcherConstrainPointOnObject::CmdSketcherConstrainPointOnObject()
|
||||
|
||||
}
|
||||
|
||||
bool CmdSketcherConstrainPointOnObject::substituteConstraintCombinations( SketchObject * Obj,
|
||||
int GeoId1, PointPos PosId1, int GeoId2)
|
||||
{
|
||||
const std::vector< Constraint * > &cvals = Obj->Constraints.getValues();
|
||||
|
||||
int cid = 0;
|
||||
for (std::vector<Constraint *>::const_iterator it = cvals.begin(); it != cvals.end(); ++it, ++cid) {
|
||||
if( (*it)->Type == Sketcher::Tangent &&
|
||||
(*it)->FirstPos == Sketcher::none && (*it)->SecondPos == Sketcher::none &&
|
||||
(*it)->Third == Constraint::GeoUndef &&
|
||||
(((*it)->First == GeoId1 && (*it)->Second == GeoId2) ||
|
||||
((*it)->Second == GeoId1 && (*it)->First == GeoId2)) ) {
|
||||
|
||||
// NOTE: This function does not either open or commit a command as it is used for group addition
|
||||
// it relies on such infrastructure being provided by the caller.
|
||||
|
||||
Gui::cmdAppObjectArgs(Obj, "delConstraint(%i)", cid);
|
||||
|
||||
doEndpointToEdgeTangency(Obj, GeoId1, PosId1, GeoId2);
|
||||
|
||||
notifyConstraintSubstitutions(QObject::tr("Endpoint to edge tangency was applied instead."));
|
||||
|
||||
getSelection().clearSelection();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CmdSketcherConstrainPointOnObject::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
@@ -2682,6 +2753,11 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(substituteConstraintCombinations(Obj, points[iPnt].GeoId, points[iPnt].PosId, curves[iCrv].GeoId)) {
|
||||
cnt++;
|
||||
continue;
|
||||
}
|
||||
|
||||
cnt++;
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
|
||||
points[iPnt].GeoId, points[iPnt].PosId, curves[iCrv].GeoId);
|
||||
@@ -2766,6 +2842,12 @@ void CmdSketcherConstrainPointOnObject::applyConstraint(std::vector<SelIdPair> &
|
||||
return;
|
||||
}
|
||||
|
||||
if(substituteConstraintCombinations(Obj, GeoIdVt, PosIdVt, GeoIdCrv)) {
|
||||
commitCommand();
|
||||
tryAutoRecompute(Obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (allOK) {
|
||||
Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
|
||||
GeoIdVt, PosIdVt, GeoIdCrv);
|
||||
@@ -4083,6 +4165,8 @@ public:
|
||||
protected:
|
||||
virtual void activated(int iMsg);
|
||||
virtual void applyConstraint(std::vector<SelIdPair> &selSeq, int seqIndex);
|
||||
// returns true if a substitution took place
|
||||
bool substituteConstraintCombinations(SketchObject * Obj, int GeoId1, int GeoId2);
|
||||
};
|
||||
|
||||
CmdSketcherConstrainTangent::CmdSketcherConstrainTangent()
|
||||
@@ -4111,6 +4195,62 @@ CmdSketcherConstrainTangent::CmdSketcherConstrainTangent()
|
||||
{SelVertexOrRoot, SelVertex} /*Two Endpoints*/ /*No Place for One Endpoint and One Curve*/};
|
||||
}
|
||||
|
||||
bool CmdSketcherConstrainTangent::substituteConstraintCombinations(SketchObject * Obj, int GeoId1, int GeoId2)
|
||||
{
|
||||
const std::vector< Constraint * > &cvals = Obj->Constraints.getValues();
|
||||
|
||||
int cid = 0;
|
||||
for (std::vector<Constraint *>::const_iterator it = cvals.begin(); it != cvals.end(); ++it, ++cid) {
|
||||
if( (*it)->Type == Sketcher::Coincident &&
|
||||
(((*it)->First == GeoId1 && (*it)->Second == GeoId2) ||
|
||||
((*it)->Second == GeoId1 && (*it)->First == GeoId2)) ) {
|
||||
|
||||
// save values because 'doEndpointTangency' changes the
|
||||
// constraint property and thus invalidates this iterator
|
||||
int first = (*it)->First;
|
||||
int firstpos = static_cast<int>((*it)->FirstPos);
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Swap coincident+tangency with ptp tangency"));
|
||||
|
||||
doEndpointTangency(Obj, (*it)->First, (*it)->Second, (*it)->FirstPos, (*it)->SecondPos);
|
||||
|
||||
Gui::cmdAppObjectArgs(Obj, "delConstraintOnPoint(%i,%i)", first, firstpos);
|
||||
|
||||
commitCommand();
|
||||
Obj->solve(); // The substitution requires a solve() so that the autoremove redundants works when Autorecompute not active.
|
||||
tryAutoRecomputeIfNotSolve(Obj);
|
||||
|
||||
notifyConstraintSubstitutions(QObject::tr("Endpoint to endpoint tangency was applied. The coincident constraint was deleted."));
|
||||
|
||||
getSelection().clearSelection();
|
||||
return true;
|
||||
}
|
||||
else if( (*it)->Type == Sketcher::PointOnObject &&
|
||||
(((*it)->First == GeoId1 && (*it)->Second == GeoId2) ||
|
||||
((*it)->Second == GeoId1 && (*it)->First == GeoId2)) ) {
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Swap PointOnObject+tangency with point to curve tangency"));
|
||||
|
||||
doEndpointToEdgeTangency(Obj, (*it)->First, (*it)->FirstPos, (*it)->Second);
|
||||
|
||||
Gui::cmdAppObjectArgs(Obj, "delConstraint(%i)", cid); // remove the preexisting point on object constraint.
|
||||
|
||||
commitCommand();
|
||||
|
||||
// A substitution requires a solve() so that the autoremove redundants works when Autorecompute not active. However,
|
||||
// delConstraint includes such solve() internally. So at this point it is already solved.
|
||||
tryAutoRecomputeIfNotSolve(Obj);
|
||||
|
||||
notifyConstraintSubstitutions(QObject::tr("Endpoint to edge tangency was applied. The point on object constraint was deleted."));
|
||||
|
||||
getSelection().clearSelection();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
@@ -4237,7 +4377,7 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
}
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add tangent constraint"));
|
||||
doEndpointTangency(Obj, selection[0], GeoId1, GeoId2, PosId1, PosId2);
|
||||
doEndpointTangency(Obj, GeoId1, GeoId2, PosId1, PosId2);
|
||||
commitCommand();
|
||||
tryAutoRecompute(Obj);
|
||||
|
||||
@@ -4301,39 +4441,13 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
QObject::tr("Select an edge that is not a B-spline weight"));
|
||||
return;
|
||||
}
|
||||
// check if there is a coincidence constraint on GeoId1, GeoId2
|
||||
const std::vector< Constraint * > &cvals = Obj->Constraints.getValues();
|
||||
|
||||
for (std::vector<Constraint *>::const_iterator it = cvals.begin(); it != cvals.end(); ++it) {
|
||||
if( (*it)->Type == Sketcher::Coincident &&
|
||||
(((*it)->First == GeoId1 && (*it)->Second == GeoId2) ||
|
||||
((*it)->Second == GeoId1 && (*it)->First == GeoId2)) ) {
|
||||
|
||||
// save values because 'doEndpointTangency' changes the
|
||||
// constraint property and thus invalidates this iterator
|
||||
int first = (*it)->First;
|
||||
int firstpos = static_cast<int>((*it)->FirstPos);
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Swap coincident+tangency with ptp tangency"));
|
||||
|
||||
doEndpointTangency(Obj, selection[0], (*it)->First, (*it)->Second, (*it)->FirstPos, (*it)->SecondPos);
|
||||
|
||||
Gui::cmdAppObjectArgs(Obj, "delConstraintOnPoint(%i,%i)", first, firstpos);
|
||||
|
||||
commitCommand();
|
||||
Obj->solve(); // The substitution requires a solve() so that the autoremove redundants works when Autorecompute not active.
|
||||
tryAutoRecomputeIfNotSolve(Obj);
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
|
||||
if(hGrp->GetBool("NotifyConstraintSubstitutions", true)) {
|
||||
QMessageBox::information(Gui::getMainWindow(), QObject::tr("Constraint Substitution"),
|
||||
QObject::tr("Endpoint to endpoint tangency was applied. The coincident constraint was deleted."));
|
||||
}
|
||||
getSelection().clearSelection();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// check if as a consequence of this command undesirable combinations of constraints would
|
||||
// arise and substitute them with more appropriate counterparts, examples:
|
||||
// - coincidence + tangency on edge
|
||||
// - point on object + tangency on edge
|
||||
if(substituteConstraintCombinations(Obj, GeoId1, GeoId2))
|
||||
return;
|
||||
|
||||
if( geom1 && geom2 &&
|
||||
( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() ||
|
||||
@@ -4526,6 +4640,12 @@ void CmdSketcherConstrainTangent::applyConstraint(std::vector<SelIdPair> &selSeq
|
||||
return;
|
||||
}
|
||||
|
||||
// check if as a consequence of this command undesirable combinations of constraints would
|
||||
// arise and substitute them with more appropriate counterparts, examples:
|
||||
// - coincidence + tangency on edge
|
||||
// - point on object + tangency on edge
|
||||
if(substituteConstraintCombinations(Obj, GeoId1, GeoId2))
|
||||
return;
|
||||
|
||||
if( geom1 && geom2 &&
|
||||
( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() ||
|
||||
|
||||
@@ -137,7 +137,14 @@ void tryAutoRecomputeIfNotSolve(Sketcher::SketchObject* obj);
|
||||
bool checkConstraint(const std::vector< Sketcher::Constraint * > &vals, Sketcher::ConstraintType type, int geoid, Sketcher::PointPos pos);
|
||||
|
||||
/// Does an endpoint-to-endpoint tangency
|
||||
void doEndpointTangency(Sketcher::SketchObject* Obj, Gui::SelectionObject &selection, int GeoId1, int GeoId2, Sketcher::PointPos PosId1, Sketcher::PointPos PosId2);
|
||||
void doEndpointTangency(Sketcher::SketchObject* Obj, int GeoId1, int GeoId2, Sketcher::PointPos PosId1, Sketcher::PointPos PosId2);
|
||||
|
||||
/// Does an endpoint-edge tangency
|
||||
void doEndpointToEdgeTangency( Sketcher::SketchObject* Obj, int GeoId1, Sketcher::PointPos PosId1, int GeoId2);
|
||||
|
||||
/// shows constraint substitution information dialog box, enabling the user to forgo further notifications
|
||||
void notifyConstraintSubstitutions(const QString & message);
|
||||
|
||||
}
|
||||
#endif // SKETCHERGUI_DrawSketchHandler_H
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <Mod/Sketcher/App/SketchObject.h>
|
||||
#include <Mod/Part/App/DatumFeature.h>
|
||||
#include <Mod/Part/App/BodyBase.h>
|
||||
#include <Mod/Sketcher/App/Constraint.h>
|
||||
|
||||
#include "ViewProviderSketch.h"
|
||||
#include "DrawSketchHandler.h"
|
||||
@@ -5450,13 +5451,15 @@ namespace SketcherGui {
|
||||
int GeoId = std::atoi(element.substr(4,4000).c_str()) - 1;
|
||||
Sketcher::SketchObject *Sketch = static_cast<Sketcher::SketchObject*>(object);
|
||||
const Part::Geometry *geom = Sketch->getGeometry(GeoId);
|
||||
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomCircle::getClassTypeId()||
|
||||
geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()||
|
||||
geom->getTypeId() == Part::GeomEllipse::getClassTypeId()||
|
||||
geom->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()
|
||||
)
|
||||
return true;
|
||||
if (geom->getTypeId().isDerivedFrom(Part::GeomTrimmedCurve::getClassTypeId()) ||
|
||||
geom->getTypeId() == Part::GeomCircle::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomEllipse::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()
|
||||
) {
|
||||
// We do not trim internal geometry of complex geometries
|
||||
if( Sketcher::GeometryFacade::isInternalType(geom, Sketcher::InternalType::None))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -5483,6 +5486,40 @@ public:
|
||||
virtual void mouseMove(Base::Vector2d onSketchPos)
|
||||
{
|
||||
Q_UNUSED(onSketchPos);
|
||||
|
||||
int GeoId = sketchgui->getPreselectCurve();
|
||||
|
||||
if (GeoId > -1) {
|
||||
auto sk = static_cast<Sketcher::SketchObject *>(sketchgui->getObject());
|
||||
int GeoId1, GeoId2;
|
||||
Base::Vector3d intersect1, intersect2;
|
||||
if(sk->seekTrimPoints(GeoId, Base::Vector3d(onSketchPos.x,onSketchPos.y,0),
|
||||
GeoId1, intersect1,
|
||||
GeoId2, intersect2)) {
|
||||
|
||||
EditMarkers.resize(0);
|
||||
|
||||
if(GeoId1 != Sketcher::Constraint::GeoUndef)
|
||||
EditMarkers.emplace_back(intersect1.x, intersect1.y);
|
||||
else {
|
||||
auto start = sk->getPoint(GeoId, Sketcher::start);
|
||||
EditMarkers.emplace_back(start.x, start.y);
|
||||
}
|
||||
|
||||
if(GeoId2 != Sketcher::Constraint::GeoUndef)
|
||||
EditMarkers.emplace_back(intersect2.x, intersect2.y);
|
||||
else {
|
||||
auto end = sk->getPoint(GeoId, Sketcher::end);
|
||||
EditMarkers.emplace_back( end.x, end.y);
|
||||
}
|
||||
|
||||
sketchgui->drawEditMarkers(EditMarkers, 2); // maker augmented by two sizes (see supported marker sizes)
|
||||
}
|
||||
}
|
||||
else {
|
||||
EditMarkers.resize(0);
|
||||
sketchgui->drawEditMarkers(EditMarkers, 2);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool pressButton(Base::Vector2d onSketchPos)
|
||||
@@ -5496,11 +5533,10 @@ public:
|
||||
int GeoId = sketchgui->getPreselectCurve();
|
||||
if (GeoId > -1) {
|
||||
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(GeoId);
|
||||
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomCircle::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomEllipse::getClassTypeId()) {
|
||||
if (geom->getTypeId().isDerivedFrom(Part::GeomTrimmedCurve::getClassTypeId()) ||
|
||||
geom->getTypeId() == Part::GeomCircle::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomEllipse::getClassTypeId() ||
|
||||
geom->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() ) {
|
||||
try {
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Trim edge"));
|
||||
Gui::cmdAppObjectArgs(sketchgui->getObject(), "trim(%d,App.Vector(%f,%f,0))",
|
||||
@@ -5513,12 +5549,17 @@ public:
|
||||
Gui::Command::abortCommand();
|
||||
}
|
||||
}
|
||||
|
||||
EditMarkers.resize(0);
|
||||
sketchgui->drawEditMarkers(EditMarkers);
|
||||
}
|
||||
else // exit the trimming tool if the user clicked on empty space
|
||||
sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
std::vector<Base::Vector2d> EditMarkers;
|
||||
};
|
||||
|
||||
DEF_STD_CMD_A(CmdSketcherTrimming)
|
||||
|
||||
@@ -72,6 +72,7 @@ void DrawSketchHandler::quit(void)
|
||||
{
|
||||
assert(sketchgui);
|
||||
sketchgui->drawEdit(std::vector<Base::Vector2d>());
|
||||
sketchgui->drawEditMarkers(std::vector<Base::Vector2d>());
|
||||
resetPositionText();
|
||||
|
||||
Gui::Selection().rmvSelectionGate();
|
||||
|
||||
@@ -196,13 +196,16 @@ struct EditData {
|
||||
CurvesMaterials(0),
|
||||
RootCrossMaterials(0),
|
||||
EditCurvesMaterials(0),
|
||||
EditMarkersMaterials(0),
|
||||
PointsCoordinate(0),
|
||||
CurvesCoordinate(0),
|
||||
RootCrossCoordinate(0),
|
||||
EditCurvesCoordinate(0),
|
||||
EditMarkersCoordinate(0),
|
||||
CurveSet(0),
|
||||
RootCrossSet(0),
|
||||
EditCurveSet(0),
|
||||
EditMarkerSet(0),
|
||||
PointSet(0),
|
||||
textX(0),
|
||||
textPos(0),
|
||||
@@ -213,6 +216,7 @@ struct EditData {
|
||||
CurvesDrawStyle(0),
|
||||
RootCrossDrawStyle(0),
|
||||
EditCurvesDrawStyle(0),
|
||||
EditMarkersDrawStyle(0),
|
||||
ConstraintDrawStyle(0),
|
||||
InformationDrawStyle(0)
|
||||
{}
|
||||
@@ -267,13 +271,16 @@ struct EditData {
|
||||
SoMaterial *CurvesMaterials;
|
||||
SoMaterial *RootCrossMaterials;
|
||||
SoMaterial *EditCurvesMaterials;
|
||||
SoMaterial *EditMarkersMaterials;
|
||||
SoCoordinate3 *PointsCoordinate;
|
||||
SoCoordinate3 *CurvesCoordinate;
|
||||
SoCoordinate3 *RootCrossCoordinate;
|
||||
SoCoordinate3 *EditCurvesCoordinate;
|
||||
SoCoordinate3 *EditMarkersCoordinate;
|
||||
SoLineSet *CurveSet;
|
||||
SoLineSet *RootCrossSet;
|
||||
SoLineSet *EditCurveSet;
|
||||
SoMarkerSet *EditMarkerSet;
|
||||
SoMarkerSet *PointSet;
|
||||
|
||||
SoText2 *textX;
|
||||
@@ -287,6 +294,7 @@ struct EditData {
|
||||
SoDrawStyle * CurvesDrawStyle;
|
||||
SoDrawStyle * RootCrossDrawStyle;
|
||||
SoDrawStyle * EditCurvesDrawStyle;
|
||||
SoDrawStyle * EditMarkersDrawStyle;
|
||||
SoDrawStyle * ConstraintDrawStyle;
|
||||
SoDrawStyle * InformationDrawStyle;
|
||||
};
|
||||
@@ -3837,6 +3845,8 @@ void ViewProviderSketch::updateInventorNodeSizes()
|
||||
edit->CurvesDrawStyle->lineWidth = 3 * edit->pixelScalingFactor;
|
||||
edit->RootCrossDrawStyle->lineWidth = 2 * edit->pixelScalingFactor;
|
||||
edit->EditCurvesDrawStyle->lineWidth = 3 * edit->pixelScalingFactor;
|
||||
edit->EditMarkersDrawStyle->pointSize = 8 * edit->pixelScalingFactor;
|
||||
edit->EditMarkerSet->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_LINE", edit->MarkerSize);
|
||||
edit->ConstraintDrawStyle->lineWidth = 1 * edit->pixelScalingFactor;
|
||||
edit->InformationDrawStyle->lineWidth = 1 * edit->pixelScalingFactor;
|
||||
}
|
||||
@@ -6144,6 +6154,47 @@ void ViewProviderSketch::drawEdit(const std::vector<Base::Vector2d> &EditCurve)
|
||||
index[0] = EditCurve.size();
|
||||
edit->EditCurvesCoordinate->point.finishEditing();
|
||||
edit->EditCurveSet->numVertices.finishEditing();
|
||||
edit->EditCurvesMaterials->diffuseColor.finishEditing();
|
||||
}
|
||||
|
||||
void ViewProviderSketch::drawEditMarkers(const std::vector<Base::Vector2d> &EditMarkers, unsigned int augmentationlevel)
|
||||
{
|
||||
assert(edit);
|
||||
|
||||
// determine marker size
|
||||
int augmentedmarkersize = edit->MarkerSize;
|
||||
|
||||
auto supportedsizes = Gui::Inventor::MarkerBitmaps::getSupportedSizes("CIRCLE_LINE");
|
||||
|
||||
auto defaultmarker = std::find(supportedsizes.begin(), supportedsizes.end(), edit->MarkerSize);
|
||||
|
||||
if(defaultmarker != supportedsizes.end()) {
|
||||
auto validAugmentationLevels = std::distance(defaultmarker,supportedsizes.end());
|
||||
|
||||
if(augmentationlevel >= validAugmentationLevels)
|
||||
augmentationlevel = validAugmentationLevels - 1;
|
||||
|
||||
augmentedmarkersize = *std::next(defaultmarker, augmentationlevel);
|
||||
}
|
||||
|
||||
edit->EditMarkerSet->markerIndex.startEditing();
|
||||
edit->EditMarkerSet->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_LINE", augmentedmarkersize);
|
||||
|
||||
// add the points to set
|
||||
edit->EditMarkersCoordinate->point.setNum(EditMarkers.size());
|
||||
edit->EditMarkersMaterials->diffuseColor.setNum(EditMarkers.size());
|
||||
SbVec3f *verts = edit->EditMarkersCoordinate->point.startEditing();
|
||||
SbColor *color = edit->EditMarkersMaterials->diffuseColor.startEditing();
|
||||
|
||||
int i=0; // setting up the line set
|
||||
for (std::vector<Base::Vector2d>::const_iterator it = EditMarkers.begin(); it != EditMarkers.end(); ++it,i++) {
|
||||
verts[i].setValue(it->x,it->y,zEdit);
|
||||
color[i] = InformationColor;
|
||||
}
|
||||
|
||||
edit->EditMarkersCoordinate->point.finishEditing();
|
||||
edit->EditMarkersMaterials->diffuseColor.finishEditing();
|
||||
edit->EditMarkerSet->markerIndex.finishEditing();
|
||||
}
|
||||
|
||||
void ViewProviderSketch::updateData(const App::Property *prop)
|
||||
@@ -6686,6 +6737,27 @@ void ViewProviderSketch::createEditInventorNodes(void)
|
||||
SbColor cursorTextColor(0,0,1);
|
||||
cursorTextColor.setPackedValue((uint32_t)hGrp->GetUnsigned("CursorTextColor", cursorTextColor.getPackedValue()), transparency);
|
||||
|
||||
// stuff for the EditMarkers +++++++++++++++++++++++++++++++++++++++
|
||||
SoSeparator* editMarkersRoot = new SoSeparator;
|
||||
edit->EditRoot->addChild(editMarkersRoot);
|
||||
edit->EditMarkersMaterials = new SoMaterial;
|
||||
edit->EditMarkersMaterials->setName("EditMarkersMaterials");
|
||||
editCurvesRoot->addChild(edit->EditMarkersMaterials);
|
||||
|
||||
edit->EditMarkersCoordinate = new SoCoordinate3;
|
||||
edit->EditMarkersCoordinate->setName("EditMarkersCoordinate");
|
||||
editCurvesRoot->addChild(edit->EditMarkersCoordinate);
|
||||
|
||||
edit->EditMarkersDrawStyle = new SoDrawStyle;
|
||||
edit->EditMarkersDrawStyle->setName("EditMarkersDrawStyle");
|
||||
edit->EditMarkersDrawStyle->pointSize = 8 * edit->pixelScalingFactor;
|
||||
editCurvesRoot->addChild(edit->EditMarkersDrawStyle);
|
||||
|
||||
edit->EditMarkerSet = new SoMarkerSet;
|
||||
edit->EditMarkerSet->setName("EditMarkerSet");
|
||||
edit->EditMarkerSet->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CIRCLE_LINE", edit->MarkerSize);
|
||||
editCurvesRoot->addChild(edit->EditMarkerSet);
|
||||
|
||||
// stuff for the edit coordinates ++++++++++++++++++++++++++++++++++++++
|
||||
SoSeparator *Coordsep = new SoSeparator();
|
||||
SoPickStyle* ps = new SoPickStyle();
|
||||
|
||||
@@ -128,6 +128,9 @@ public:
|
||||
/// draw the edit curve
|
||||
void drawEdit(const std::vector<Base::Vector2d> &EditCurve);
|
||||
|
||||
/// draw the edit markers
|
||||
void drawEditMarkers(const std::vector<Base::Vector2d> &EditMarkers, unsigned int augmentationlevel = 0);
|
||||
|
||||
/// Is the view provider selectable
|
||||
bool isSelectable(void) const override;
|
||||
/// Observer message from the Selection
|
||||
|
||||
Reference in New Issue
Block a user