Merge branch 'master' into bugfix/dogbone-on-straight-edges-and-noop-moves

This commit is contained in:
mlampert
2021-03-22 10:52:08 -07:00
committed by GitHub
37 changed files with 1760 additions and 1427 deletions
+29 -6
View File
@@ -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();
}
+12 -2
View File
@@ -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
+8 -6
View File
@@ -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
View File
@@ -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
+2 -1
View File
@@ -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:
+3 -1
View File
@@ -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();
+1 -1
View File
@@ -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:
+2
View File
@@ -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
)
+5 -4
View File
@@ -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.83e3 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
View File
@@ -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();
}
+2
View File
@@ -329,6 +329,8 @@ SET(Mesh_SRCS
AppMeshPy.cpp
Exporter.cpp
Exporter.h
Importer.cpp
Importer.h
Facet.cpp
Facet.h
FacetPyImp.cpp
+1 -7
View File
@@ -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);
+123
View File
@@ -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;
}
+63
View File
@@ -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
+31
View File
@@ -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
+2
View File
@@ -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;
+17 -17
View File
@@ -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;
}
+8 -6
View File
@@ -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;
+22 -7
View File
@@ -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())
+1
View File
@@ -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;
+76 -36
View File
@@ -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());
+3 -1
View File
@@ -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;
+110 -93
View File
@@ -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
+61 -1
View File
@@ -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
+197 -77
View File
@@ -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() ||
+8 -1
View File
@@ -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
+53 -12
View File
@@ -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