From 4fdec77034d51be85a3e4f925a970991c94cb38c Mon Sep 17 00:00:00 2001 From: IMback Date: Thu, 8 Aug 2019 10:38:30 +0200 Subject: [PATCH 1/8] Peck retract height default changed from 10mm to opStartDepth+1 Peck depth default changed to tool dia*0.75 Fields changed to QuanitiySpinBoxes Insure travel between regions is always performed at safe height Make Peck and Dwell exclusive in GUI Restore name of RetractHeight Use SetupSheet for all numerical properties --- .../Resources/panels/PageOpDrillingEdit.ui | 87 +++++++++++-------- src/Mod/Path/PathScripts/PathDrilling.py | 46 ++++++---- src/Mod/Path/PathScripts/PathDrillingGui.py | 50 +++++++++-- src/Mod/Path/PathScripts/PathGui.py | 5 ++ src/Mod/Path/PathScripts/PathOpGui.py | 1 + 5 files changed, 130 insertions(+), 59 deletions(-) diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpDrillingEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpDrillingEdit.ui index c4d2e3530b..b1ad210bb3 100644 --- a/src/Mod/Path/Gui/Resources/panels/PageOpDrillingEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/PageOpDrillingEdit.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 255 + 572 + 299 @@ -49,55 +49,75 @@ - - + + - Dwell + Use Tip Length - - + + + + false + - 0 sec - - - sec + Time - - - - mm + + + + false - - - - - Retract Height + Depth - + + + + false + + + Retract + + + + + + + false + + + + Peck - - - - mm + + + + Dwell - - - - Use Tip Length + + + + false + + + + + + + false @@ -121,18 +141,15 @@ - Gui::InputField - QLineEdit -
Gui/InputField.h
+ Gui::QuantitySpinBox + QDoubleSpinBox +
Gui/QuantitySpinBox.h
toolController - retractHeight peckEnabled - peckDepth dwellEnabled - dwellTime useTipLength diff --git a/src/Mod/Path/PathScripts/PathDrilling.py b/src/Mod/Path/PathScripts/PathDrilling.py index 70b3306832..ee58d3e335 100644 --- a/src/Mod/Path/PathScripts/PathDrilling.py +++ b/src/Mod/Path/PathScripts/PathDrilling.py @@ -43,7 +43,7 @@ __title__ = "Path Drilling Operation" __author__ = "sliptonic (Brad Collette)" __url__ = "http://www.freecadweb.org" __doc__ = "Path Drilling operation." -__contributors__ = "russ4262 (Russell Johnson)" +__contributors__ = "russ4262 (Russell Johnson), IMBack!" __created__ = "2014" __scriptVersion__ = "1c testing" __lastModified__ = "2019-06-25 14:49 CST" @@ -77,10 +77,9 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): obj.addProperty("App::PropertyFloat", "DwellTime", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "The time to dwell between peck cycles")) obj.addProperty("App::PropertyBool", "DwellEnabled", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "Enable dwell")) obj.addProperty("App::PropertyBool", "AddTipLength", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "Calculate the tip length and subtract from final depth")) - obj.addProperty("App::PropertyEnumeration", "ReturnLevel", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "Controls how tool retracts Default=G98")) - obj.ReturnLevel = ['G98', 'G99'] # this is the direction that the Contour runs - - obj.addProperty("App::PropertyDistance", "RetractHeight", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height where feed starts and height during retract tool when path is finished")) + obj.addProperty("App::PropertyEnumeration", "ReturnLevel", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "Controls how tool retracts Default=G99")) + obj.ReturnLevel = ['G99', 'G98'] # Canned Cycle Return Level + obj.addProperty("App::PropertyDistance", "RetractHeight", "Drill", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height where feed starts and height during retract tool when path is finished while in a peck operation")) # Rotation related properties if not hasattr(obj, 'EnableRotation'): @@ -116,20 +115,14 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): self.commandlist.append(Path.Command('G90')) self.commandlist.append(Path.Command(obj.ReturnLevel)) - # ml: I'm not sure whey these were here, they seem redundant - # # rapid to first hole location, with spindle still retracted: - # p0 = holes[0] - # self.commandlist.append(Path.Command('G0', {'X': p0['x'], 'Y': p0['y'], 'F': self.horizRapid})) - # # move tool to clearance plane - # self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid})) - for p in holes: cmd = "G81" cmdParams = {} cmdParams['Z'] = p['trgtDep'] - tiplength cmdParams['F'] = self.vertFeed - cmdParams['R'] = obj.RetractHeight.Value + cmdParams['R'] = obj.SafeHeight.Value if obj.PeckEnabled and obj.PeckDepth.Value > 0: + cmdParams['R'] = obj.RetractHeight.Value cmd = "G83" cmdParams['Q'] = obj.PeckDepth.Value elif obj.DwellEnabled and obj.DwellTime > 0: @@ -172,23 +165,45 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): self.commandlist.append(Path.Command('G0', {axisOfRot: angle, 'F': self.axialRapid})) self.commandlist.append(Path.Command('G0', {'X': p['x'], 'Y': p['y'], 'F': self.horizRapid})) self.commandlist.append(Path.Command('G1', {'Z': p['stkTop'], 'F': self.vertFeed})) - + # Perform and cancel canned drilling cycle self.commandlist.append(Path.Command(cmd, params)) self.commandlist.append(Path.Command('G80')) + + # shift axis and angle values if obj.EnableRotation != 'Off': lastAxis = axisOfRot lastAngle = angle + elif obj.PeckEnabled and obj.PeckDepth.Value > 0 and obj.RetractHeight.Value != obj.SafeHeight.Value: + self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value})) if obj.EnableRotation != 'Off': self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid})) self.commandlist.append(Path.Command('G0', {lastAxis: 0.0, 'F': self.axialRapid})) + def opSetDefaultValues(self, obj, job): '''opSetDefaultValues(obj, job) ... set default value for RetractHeight''' - obj.RetractHeight = 10.0 + + parentJob = PathUtils.findParentJob(obj) + + if hasattr(parentJob.SetupSheet, 'RetractHeight'): + obj.RetractHeight = parentJob.SetupSheet.RetractHeight + elif self.applyExpression(obj, 'RetractHeight', 'OpStartDepth+1mm'): + obj.RetractHeight = 10 + + if hasattr(parentJob.SetupSheet, 'PeckDepth'): + obj.PeckDepth = parentJob.SetupSheet.PeckDepth + elif self.applyExpression(obj, 'PeckDepth', 'OpToolDiameter*0.75'): + obj.PeckDepth = 1 + + if hasattr(parentJob.SetupSheet, 'DwellTime'): + obj.DwellTime = parentJob.SetupSheet.DwellTime + else: + obj.DwellTime = 1 + obj.ReverseDirection = False obj.InverseAngle = False obj.B_AxisErrorOverride = False @@ -196,7 +211,6 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): # Initial setting for EnableRotation is taken from Job SetupSheet # User may override on per-operation basis as needed. - parentJob = PathUtils.findParentJob(obj) if hasattr(parentJob.SetupSheet, 'SetupEnableRotation'): obj.EnableRotation = parentJob.SetupSheet.SetupEnableRotation else: diff --git a/src/Mod/Path/PathScripts/PathDrillingGui.py b/src/Mod/Path/PathScripts/PathDrillingGui.py index 3415e76f0a..8b053ec6eb 100644 --- a/src/Mod/Path/PathScripts/PathDrillingGui.py +++ b/src/Mod/Path/PathScripts/PathDrillingGui.py @@ -36,6 +36,7 @@ __title__ = "Path Drilling Operation UI." __author__ = "sliptonic (Brad Collette)" __url__ = "http://www.freecadweb.org" __doc__ = "UI and Command for Path Drilling Operation." +__contributors__ = "IMBack!" LOGLEVEL = False @@ -48,17 +49,49 @@ else: class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage): '''Controller for the drilling operation's page''' + + def initPage(self, obj): + self.peckDepthSpinBox = PathGui.QuantitySpinBox(self.form.peckDepth, obj, 'PeckDepth') + self.peckRetractSpinBox = PathGui.QuantitySpinBox(self.form.peckRetractHeight, obj, 'RetractHeight') + self.dwellTimeSpinBox = PathGui.QuantitySpinBox(self.form.dwellTime, obj, 'DwellTime') + + def registerSignalHandlers(self, obj): + self.form.peckEnabled.toggled.connect(self.form.peckDepth.setEnabled) + self.form.peckEnabled.toggled.connect(self.form.peckRetractHeight.setEnabled) + self.form.peckEnabled.toggled.connect(self.form.peckDepthLabel.setEnabled) + self.form.peckEnabled.toggled.connect(self.form.retractLabel.setEnabled) + self.form.peckEnabled.toggled.connect(self.form.dwellEnabled.setDisabled) + + self.form.dwellEnabled.toggled.connect(self.form.dwellTime.setEnabled) + self.form.dwellEnabled.toggled.connect(self.form.dwellTimelabel.setEnabled) + self.form.dwellEnabled.toggled.connect(self.form.peckEnabled.setDisabled) + + if self.form.peckEnabled.isChecked(): + self.form.dwellEnabled.setEnabled(False) + self.form.peckDepth.setEnabled(True) + self.form.peckRetractHeight.setEnabled(True) + self.form.peckDepthLabel.setEnabled(True) + self.form.retractLabel.setEnabled(True) + elif self.form.dwellEnabled.isChecked(): + self.form.peckEnabled.setEnabled(False) + self.form.dwellTime.setEnabled(True) + self.form.dwellTimelabel.setEnabled(True) def getForm(self): '''getForm() ... return UI''' return FreeCADGui.PySideUic.loadUi(":/panels/PageOpDrillingEdit.ui") + + def updateQuantitySpinBoxes(self, index = None): + self.peckDepthSpinBox.updateSpinBox() + self.peckRetractSpinBox.updateSpinBox() + self.dwellTimeSpinBox.updateSpinBox() def getFields(self, obj): '''setFields(obj) ... update obj's properties with values from the UI''' PathLog.track() - PathGui.updateInputField(obj, 'PeckDepth', self.form.peckDepth) - PathGui.updateInputField(obj, 'RetractHeight', self.form.retractHeight) - PathGui.updateInputField(obj, 'DwellTime', self.form.dwellTime) + self.peckDepthSpinBox.updateProperty() + self.peckRetractSpinBox.updateProperty() + self.dwellTimeSpinBox.updateProperty() if obj.DwellEnabled != self.form.dwellEnabled.isChecked(): obj.DwellEnabled = self.form.dwellEnabled.isChecked() @@ -72,10 +105,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage): def setFields(self, obj): '''setFields(obj) ... update UI with obj properties' values''' PathLog.track() - - self.form.peckDepth.setText(FreeCAD.Units.Quantity(obj.PeckDepth.Value, FreeCAD.Units.Length).UserString) - self.form.retractHeight.setText(FreeCAD.Units.Quantity(obj.RetractHeight.Value, FreeCAD.Units.Length).UserString) - self.form.dwellTime.setText(str(obj.DwellTime)) + self.updateQuantitySpinBoxes() if obj.DwellEnabled: self.form.dwellEnabled.setCheckState(QtCore.Qt.Checked) @@ -98,7 +128,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage): '''getSignalsForUpdate(obj) ... return list of signals which cause the receiver to update the model''' signals = [] - signals.append(self.form.retractHeight.editingFinished) + signals.append(self.form.peckRetractHeight.editingFinished) signals.append(self.form.peckDepth.editingFinished) signals.append(self.form.dwellTime.editingFinished) signals.append(self.form.dwellEnabled.stateChanged) @@ -107,6 +137,10 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage): signals.append(self.form.toolController.currentIndexChanged) return signals + + def updateData(self, obj, prop): + if prop in ['PeckDepth', 'RetractHeight'] and not prop in ['Base', 'Disabled']: + self.updateQuantitySpinBoxes() Command = PathOpGui.SetupOperation('Drilling', PathDrilling.Create, diff --git a/src/Mod/Path/PathScripts/PathGui.py b/src/Mod/Path/PathScripts/PathGui.py index cd00faac57..ed2e9e757d 100644 --- a/src/Mod/Path/PathScripts/PathGui.py +++ b/src/Mod/Path/PathScripts/PathGui.py @@ -122,6 +122,11 @@ The spin box gets bound to a given property and supports update in both directio if self.valid: return self.widget.property('expression') return '' + + def setMinimum(self, quantity): + if self.valid: + value = quantity.Value if hasattr(quantity, 'Value') else quantity + self.widget.setProperty('setMinimum', value) def updateSpinBox(self, quantity=None): '''updateSpinBox(quantity=None) ... update the display value of the spin box. diff --git a/src/Mod/Path/PathScripts/PathOpGui.py b/src/Mod/Path/PathScripts/PathOpGui.py index ac037a578c..c350c68e87 100644 --- a/src/Mod/Path/PathScripts/PathOpGui.py +++ b/src/Mod/Path/PathScripts/PathOpGui.py @@ -354,6 +354,7 @@ class TaskPanelPage(object): controllers = PathUtils.getToolControllers(self.obj) labels = [c.Label for c in controllers] combo.blockSignals(True) + combo.clear() combo.addItems(labels) combo.blockSignals(False) From ac16f2f6733b2580d03e69a8fd851566b3200a0c Mon Sep 17 00:00:00 2001 From: IMback Date: Thu, 8 Aug 2019 19:29:26 +0200 Subject: [PATCH 2/8] Restore R parameter behavior --- src/Mod/Path/PathScripts/PathDrilling.py | 9 +++------ src/Mod/Path/PathScripts/PathDrillingGui.py | 8 +++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDrilling.py b/src/Mod/Path/PathScripts/PathDrilling.py index ee58d3e335..8ab8b713c9 100644 --- a/src/Mod/Path/PathScripts/PathDrilling.py +++ b/src/Mod/Path/PathScripts/PathDrilling.py @@ -114,15 +114,14 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): holes = PathUtils.sort_jobs(holes, ['x', 'y']) self.commandlist.append(Path.Command('G90')) self.commandlist.append(Path.Command(obj.ReturnLevel)) - + for p in holes: cmd = "G81" cmdParams = {} cmdParams['Z'] = p['trgtDep'] - tiplength cmdParams['F'] = self.vertFeed - cmdParams['R'] = obj.SafeHeight.Value + cmdParams['R'] = obj.RetractHeight.Value if obj.PeckEnabled and obj.PeckDepth.Value > 0: - cmdParams['R'] = obj.RetractHeight.Value cmd = "G83" cmdParams['Q'] = obj.PeckDepth.Value elif obj.DwellEnabled and obj.DwellTime > 0: @@ -168,7 +167,7 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): # Perform and cancel canned drilling cycle self.commandlist.append(Path.Command(cmd, params)) - self.commandlist.append(Path.Command('G80')) + self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value})) @@ -176,8 +175,6 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp): if obj.EnableRotation != 'Off': lastAxis = axisOfRot lastAngle = angle - elif obj.PeckEnabled and obj.PeckDepth.Value > 0 and obj.RetractHeight.Value != obj.SafeHeight.Value: - self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value})) if obj.EnableRotation != 'Off': self.commandlist.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid})) diff --git a/src/Mod/Path/PathScripts/PathDrillingGui.py b/src/Mod/Path/PathScripts/PathDrillingGui.py index 8b053ec6eb..a8eacaf961 100644 --- a/src/Mod/Path/PathScripts/PathDrillingGui.py +++ b/src/Mod/Path/PathScripts/PathDrillingGui.py @@ -57,21 +57,19 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage): def registerSignalHandlers(self, obj): self.form.peckEnabled.toggled.connect(self.form.peckDepth.setEnabled) - self.form.peckEnabled.toggled.connect(self.form.peckRetractHeight.setEnabled) - self.form.peckEnabled.toggled.connect(self.form.peckDepthLabel.setEnabled) - self.form.peckEnabled.toggled.connect(self.form.retractLabel.setEnabled) self.form.peckEnabled.toggled.connect(self.form.dwellEnabled.setDisabled) self.form.dwellEnabled.toggled.connect(self.form.dwellTime.setEnabled) self.form.dwellEnabled.toggled.connect(self.form.dwellTimelabel.setEnabled) self.form.dwellEnabled.toggled.connect(self.form.peckEnabled.setDisabled) + self.form.peckRetractHeight.setEnabled(True) + self.form.retractLabel.setEnabled(True) + if self.form.peckEnabled.isChecked(): self.form.dwellEnabled.setEnabled(False) self.form.peckDepth.setEnabled(True) - self.form.peckRetractHeight.setEnabled(True) self.form.peckDepthLabel.setEnabled(True) - self.form.retractLabel.setEnabled(True) elif self.form.dwellEnabled.isChecked(): self.form.peckEnabled.setEnabled(False) self.form.dwellTime.setEnabled(True) From 632eb83cc105c8f70a0ab11c44dffe36fecf2997 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 26 Aug 2019 14:08:53 +0200 Subject: [PATCH 3/8] add CMakeLists.txt.user to ignore list --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7cb7c65ab6..98e73eaa8c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ ui_*.h moc_*.cpp Makefile CMakeCache.txt +CMakeLists.txt.user config.h install_manifest.txt /bin/ From 76be82dc2e34e7f9898fac8e25d7153e539ea522 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Sun, 25 Aug 2019 19:07:19 -0400 Subject: [PATCH 4/8] [Gui]Add options for page size, lineWidth and background --- src/Gui/SoFCVectorizeSVGAction.cpp | 27 +++++++++++++++++++-------- src/Gui/SoFCVectorizeSVGAction.h | 10 ++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/Gui/SoFCVectorizeSVGAction.cpp b/src/Gui/SoFCVectorizeSVGAction.cpp index e36a366a9a..893e0f2190 100644 --- a/src/Gui/SoFCVectorizeSVGAction.cpp +++ b/src/Gui/SoFCVectorizeSVGAction.cpp @@ -31,6 +31,7 @@ #include #include +#include #include "SoFCVectorizeSVGAction.h" using namespace Gui; @@ -306,7 +307,7 @@ void SoFCVectorizeSVGActionP::printTriangle(const SbVec3f * v, const SbColor * c << "; stroke:#" << std::hex << std::setw(6) << std::setfill('0') << (cc >> 8) << ";" << std::endl - << " stroke-width:1.0;" << std::endl + << " stroke-width:" << publ->getLineWidth() << ";" << std::endl << " stroke-linecap:round;stroke-linejoin:round\"/>" << std::endl; } @@ -350,8 +351,9 @@ void SoFCVectorizeSVGActionP::printLine(const SoVectorizeLine * item) const << "x1=\"" << v[0][0] << "\" y1=\"" << v[0][1] << "\" " << "x2=\"" << v[1][0] << "\" y2=\"" << v[1][1] << "\" " << "stroke=\"#" - << std::hex << std::setw(6) << std::setfill('0') << (cc >> 8) - << "\" stroke-width=\"1px\" />\n"; + << std::hex << std::setw(6) << std::setfill('0') << (cc >> 8) << "\"" + << " stroke-linecap=\"square\" " + << " stroke-width=\"" << publ->getLineWidth() << "\" />\n"; } void SoFCVectorizeSVGActionP::printPoint(const SoVectorizePoint * item) const @@ -375,7 +377,10 @@ void SoFCVectorizeSVGAction::initClass(void) SO_ACTION_INIT_CLASS(SoFCVectorizeSVGAction, SoVectorizeAction); } -SoFCVectorizeSVGAction::SoFCVectorizeSVGAction() +SoFCVectorizeSVGAction::SoFCVectorizeSVGAction() : + m_backgroundState(true), + m_lineWidth(1.0), + m_usemm(false) { SO_ACTION_CONSTRUCTOR(SoFCVectorizeSVGAction); this->setOutput(new SoSVGVectorOutput); @@ -400,12 +405,18 @@ void SoFCVectorizeSVGAction::printHeader(void) const str << "" << std::endl; str << "getOrientation() == LANDSCAPE) + if (this->getOrientation() == LANDSCAPE) { SbSwap(size[0], size[1]); - str << " width=\"" << size[0] << "\" height=\"" << size[1] << "\">" << std::endl; + } + if (getUseMM()) { + str << " width=\"" << size[0] << "mm\" height=\"" << size[1] << "mm\""<< std::endl; + str << " viewBox=\"0 0 " << size[0] << " " << size[1] << "\">" << std::endl; + } else { //original code used px + str << " width=\"" << size[0] << "\" height=\"" << size[1] << "\">" << std::endl; + } str << "" << std::endl; } @@ -447,7 +458,7 @@ void SoFCVectorizeSVGAction::printBackground(void) const str << " style=\"fill:#" << std::hex << std::setw(6) << std::setfill('0') << (cc >> 8) << ";fill-opacity:1;fill-rule:evenodd;stroke:none;" - "stroke-width:1px;stroke-linecap:butt;stroke-linejoin:" + "stroke-width:" << getLineWidth() << ";stroke-linecap:butt;stroke-linejoin:" "miter;stroke-opacity:1\" />\n"; str << "" << std::endl; } diff --git a/src/Gui/SoFCVectorizeSVGAction.h b/src/Gui/SoFCVectorizeSVGAction.h index bf6a750fc5..9728d13423 100644 --- a/src/Gui/SoFCVectorizeSVGAction.h +++ b/src/Gui/SoFCVectorizeSVGAction.h @@ -62,6 +62,13 @@ public: static void initClass(void); SoSVGVectorOutput * getSVGOutput(void) const; + virtual void setBackgroundState(bool b) { m_backgroundState = b; } + virtual bool getBackgroundState(void) const { return m_backgroundState; } + virtual void setLineWidth(double w) { m_lineWidth = w; } + virtual double getLineWidth(void) const { return m_lineWidth; } + virtual void setUseMM(bool b) { m_usemm = b; } + virtual bool getUseMM(void) const { return m_usemm; } + protected: virtual void printHeader(void) const; virtual void printFooter(void) const; @@ -72,6 +79,9 @@ protected: private: SoFCVectorizeSVGActionP* p; friend class SoFCVectorizeSVGActionP; + bool m_backgroundState; + double m_lineWidth; + bool m_usemm; }; } // namespace Gui From 20612ee9b7daacae14c8e90e20659ff1b3156777 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 25 Aug 2019 10:27:24 +1000 Subject: [PATCH 5/8] Refactor exportIFC to not use global preferences --- src/Mod/Arch/exportIFC.py | 143 +++++++++++++++++--------------------- src/Mod/Arch/importIFC.py | 2 +- 2 files changed, 65 insertions(+), 80 deletions(-) diff --git a/src/Mod/Arch/exportIFC.py b/src/Mod/Arch/exportIFC.py index 019fe55d99..eaed5a81ac 100644 --- a/src/Mod/Arch/exportIFC.py +++ b/src/Mod/Arch/exportIFC.py @@ -52,8 +52,6 @@ from importIFCHelper import decode # # This module provides tools to export IFC files. -DEBUG = False # Set to True to see debug messages. Otherwise, totally silent - if open.__module__ in ['__builtin__','io']: pyopen = open # pyopen is use in exporter to open a file in Arch @@ -116,54 +114,38 @@ def getPreferences(): """retrieves IFC preferences""" - global DEBUG, PREFIX_NUMBERS, SKIP, SEPARATE_OPENINGS - global ROOT_ELEMENT, GET_EXTRUSIONS, MERGE_MATERIALS - global MERGE_MODE_ARCH, MERGE_MODE_STRUCT, CREATE_CLONES - global FORCE_BREP, IMPORT_PROPERTIES, STORE_UID, SERIALIZE - global SPLIT_LAYERS, EXPORT_2D, FULL_PARAMETRIC, FITVIEW_ONIMPORT - global ADD_DEFAULT_SITE, ADD_DEFAULT_STOREY, ADD_DEFAULT_BUILDING p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") + if FreeCAD.GuiUp and p.GetBool("ifcShowDialog",False): import FreeCADGui FreeCADGui.showPreferences("Import-Export",0) - DEBUG = p.GetBool("ifcDebug",False) - PREFIX_NUMBERS = p.GetBool("ifcPrefixNumbers",False) - SKIP = p.GetString("ifcSkip","").split(",") - SEPARATE_OPENINGS = p.GetBool("ifcSeparateOpenings",False) - ROOT_ELEMENT = p.GetString("ifcRootElement","IfcProduct") - GET_EXTRUSIONS = p.GetBool("ifcGetExtrusions",False) - MERGE_MATERIALS = p.GetBool("ifcMergeMaterials",False) - MERGE_MODE_ARCH = p.GetInt("ifcImportModeArch",0) - MERGE_MODE_STRUCT = p.GetInt("ifcImportModeStruct",1) - if MERGE_MODE_ARCH > 0: - SEPARATE_OPENINGS = False - GET_EXTRUSIONS = False - if not SEPARATE_OPENINGS: - SKIP.append("IfcOpeningElement") - CREATE_CLONES = p.GetBool("ifcCreateClones",True) - FORCE_BREP = p.GetBool("ifcExportAsBrep",False) - IMPORT_PROPERTIES = p.GetBool("ifcImportProperties",False) - STORE_UID = p.GetBool("ifcStoreUid",True) - SERIALIZE = p.GetBool("ifcSerialize",False) - SPLIT_LAYERS = p.GetBool("ifcSplitLayers",False) - EXPORT_2D = p.GetBool("ifcExport2D",True) - FULL_PARAMETRIC = p.GetBool("IfcExportFreeCADProperties",False) - FITVIEW_ONIMPORT = p.GetBool("ifcFitViewOnImport",False) - ADD_DEFAULT_SITE = p.GetBool("IfcAddDefaultSite",False) - ADD_DEFAULT_STOREY = p.GetBool("IfcAddDefaultStorey",False) - ADD_DEFAULT_BUILDING = p.GetBool("IfcAddDefaultBuilding",True) + preferences = { + 'DEBUG': p.GetBool("ifcDebug",False), + 'CREATE_CLONES': p.GetBool("ifcCreateClones",True), + 'FORCE_BREP': p.GetBool("ifcExportAsBrep",False), + 'STORE_UID': p.GetBool("ifcStoreUid",True), + 'SERIALIZE': p.GetBool("ifcSerialize",False), + 'EXPORT_2D': p.GetBool("ifcExport2D",True), + 'FULL_PARAMETRIC': p.GetBool("IfcExportFreeCADProperties",False), + 'ADD_DEFAULT_SITE': p.GetBool("IfcAddDefaultSite",False), + 'ADD_DEFAULT_STOREY': p.GetBool("IfcAddDefaultStorey",False), + 'ADD_DEFAULT_BUILDING': p.GetBool("IfcAddDefaultBuilding",True) + } + + return preferences # ************************************************************************************************ # ********** export IFC **************** -def export(exportList,filename,colors=None): +def export(exportList,filename,colors=None,preferences=None): - """export(exportList,filename,colors=None) -- exports FreeCAD contents to an IFC file. + """export(exportList,filename,colors=None,preferences=None) -- exports FreeCAD contents to an IFC file. colors is an optional dictionary of objName:shapeColorTuple or objName:diffuseColorList elements to be used in non-GUI mode if you want to be able to export colors.""" - getPreferences() + if preferences is None: + preferences = getPreferences() try: global ifcopenshell @@ -189,7 +171,7 @@ def export(exportList,filename,colors=None): schema = ["IFC4", "IFC2X3"][FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("IfcVersion",0)] else: schema = "IFC2X3" - if DEBUG: print("Exporting an",schema,"file...") + if preferences['DEBUG']: print("Exporting an",schema,"file...") template = template.replace("$ifcschema",schema) template = template.replace("$owner",owner) template = template.replace("$company",FreeCAD.ActiveDocument.Company) @@ -224,7 +206,7 @@ def export(exportList,filename,colors=None): objectslist = [obj for obj in objectslist if obj not in annotations] objectslist = Arch.pruneIncluded(objectslist,strict=True) objectslist = [obj for obj in objectslist if Draft.getType(obj) not in ["Dimension","Material","MaterialContainer","WorkingPlaneProxy"]] - if FULL_PARAMETRIC: + if preferences['FULL_PARAMETRIC']: objectslist = Arch.getAllChildren(objectslist) contextCreator = exportIFCHelper.ContextCreator(ifcfile, objectslist) @@ -254,7 +236,7 @@ def export(exportList,filename,colors=None): # build clones table - if CREATE_CLONES: + if preferences['CREATE_CLONES']: for o in objectslist: b = Draft.getCloneBase(o,strict=True) if b: @@ -292,7 +274,7 @@ def export(exportList,filename,colors=None): if not uid: uid = ifcopenshell.guid.new() # storing the uid for further use - if STORE_UID and hasattr(obj,"IfcData"): + if preferences['STORE_UID'] and hasattr(obj,"IfcData"): d = obj.IfcData d["IfcUID"] = uid obj.IfcData = d @@ -347,7 +329,7 @@ def export(exportList,filename,colors=None): if len(ifcaxes) > 2: w = ifcaxes[2] if u and v: - if DEBUG: print(str(count).ljust(3)," : ", ifctype, " (",str(len(ifcpols)),"axes ) : ",name) + if preferences['DEBUG']: print(str(count).ljust(3)," : ", ifctype, " (",str(len(ifcpols)),"axes ) : ",name) xvc = ifcbin.createIfcDirection((1.0,0.0,0.0)) zvc = ifcbin.createIfcDirection((0.0,0.0,1.0)) ovc = ifcbin.createIfcCartesianPoint((0.0,0.0,0.0)) @@ -375,12 +357,12 @@ def export(exportList,filename,colors=None): # getting the representation - representation,placement,shapetype = getRepresentation(ifcfile,context,obj,forcebrep=(brepflag or FORCE_BREP),colors=colors) + representation,placement,shapetype = getRepresentation(ifcfile,context,obj,forcebrep=(brepflag or preferences['FORCE_BREP']),colors=colors,preferences=preferences) if getstd: if isStandardCase(obj,ifctype): ifctype += "StandardCase" - if DEBUG: print(str(count).ljust(3)," : ", ifctype, " (",shapetype,") : ",name) + if preferences['DEBUG']: print(str(count).ljust(3)," : ", ifctype, " (",shapetype,") : ",name) # setting the arguments @@ -417,8 +399,8 @@ def export(exportList,filename,colors=None): if hasattr(obj,"Additions") and (shapetype in ["extrusion","no shape"]): for o in obj.Additions: - r2,p2,c2 = getRepresentation(ifcfile,context,o,colors=colors) - if DEBUG: print(" adding ",c2," : ",o.Label) + r2,p2,c2 = getRepresentation(ifcfile,context,o,colors=colors,preferences=preferences) + if preferences['DEBUG']: print(" adding ",c2," : ",o.Label) l = o.Label if six.PY2: l = l.encode("utf8") @@ -454,8 +436,8 @@ def export(exportList,filename,colors=None): guests.append(o) if hasattr(obj,"Subtractions") and (shapetype in ["extrusion","no shape"]): for o in obj.Subtractions + guests: - r2,p2,c2 = getRepresentation(ifcfile,context,o,subtraction=True,colors=colors) - if DEBUG: print(" subtracting ",c2," : ",o.Label) + r2,p2,c2 = getRepresentation(ifcfile,context,o,subtraction=True,colors=colors,preferences=preferences) + if preferences['DEBUG']: print(" subtracting ",c2," : ",o.Label) l = o.Label if six.PY2: l = l.encode("utf8") @@ -494,7 +476,7 @@ def export(exportList,filename,colors=None): psets = {} for key,value in obj.IfcProperties.items(): - pset, pname, ptype, pvalue = getPropertyData(key,value) + pset, pname, ptype, pvalue = getPropertyData(key,value,preferences) p = ifcbin.createIfcPropertySingleValue(str(pname),str(ptype),pvalue) psets.setdefault(pset,[]).append(p) for pname,props in psets.items(): @@ -565,7 +547,7 @@ def export(exportList,filename,colors=None): for cat in propertiesDic: props = [] for prop in propertiesDic[cat]: - if DEBUG: + if preferences['DEBUG']: print("key",prop["key"],type(prop["key"])) print("tp",prop["tp"],type(prop["tp"])) print("val",prop["val"],type(prop["val"])) @@ -593,7 +575,7 @@ def export(exportList,filename,colors=None): if obj.IfcData: ifcprop = True - #if DEBUG : print(" adding ifc attributes") + #if preferences['DEBUG'] : print(" adding ifc attributes") props = [] for key in obj.IfcData: if not (key in ["attributes", "complex_attributes", "IfcUID", "FlagForceBrep"]): @@ -609,7 +591,7 @@ def export(exportList,filename,colors=None): val = "(".join(r[1:]) val = val.strip("'") val = val.strip('"') - #if DEBUG: print(" property ",key," : ",val.encode("utf8"), " (", str(tp), ")") + #if preferences['DEBUG']: print(" property ",key," : ",val.encode("utf8"), " (", str(tp), ")") if tp in ["IfcLabel","IfcText","IfcIdentifier",'IfcDescriptiveMeasure']: if six.PY2: val = val.encode("utf8") @@ -641,7 +623,7 @@ def export(exportList,filename,colors=None): ) if not ifcprop: - #if DEBUG : print("no ifc properties to export") + #if preferences['DEBUG'] : print("no ifc properties to export") pass # Quantities @@ -676,7 +658,7 @@ def export(exportList,filename,colors=None): [product],eltq ) - if FULL_PARAMETRIC: + if preferences['FULL_PARAMETRIC']: # exporting all the object properties @@ -737,7 +719,7 @@ def export(exportList,filename,colors=None): itype = "IfcText" ivalue = "FreeCADLink_" + t.Name else: - if DEBUG: print("Unable to encode property ",prop," of type ",ptype) + if preferences['DEBUG']: print("Unable to encode property ",prop," of type ",ptype) if itype: # TODO add description if realm == "Gui": @@ -870,7 +852,7 @@ def export(exportList,filename,colors=None): childfloors ) buildings.append(b) - if not defaulthost and not ADD_DEFAULT_STOREY: + if not defaulthost and not preferences['ADD_DEFAULT_STOREY']: defaulthost = b # sites @@ -892,8 +874,8 @@ def export(exportList,filename,colors=None): # add default site, building and storey as required if not sites: - if ADD_DEFAULT_SITE: - if DEBUG: print("No site found. Adding default site") + if preferences['ADD_DEFAULT_SITE']: + if preferences['DEBUG']: print("No site found. Adding default site") sites = [ifcfile.createIfcSite( ifcopenshell.guid.new(), history,"Default Site", @@ -918,8 +900,8 @@ def export(exportList,filename,colors=None): project,sites ) if not buildings: - if ADD_DEFAULT_BUILDING: - if DEBUG: print("No building found. Adding default building") + if preferences['ADD_DEFAULT_BUILDING']: + if preferences['DEBUG']: print("No building found. Adding default building") buildings = [ifcfile.createIfcBuilding( ifcopenshell.guid.new(), history, @@ -973,7 +955,7 @@ def export(exportList,filename,colors=None): untreated.append(v) if untreated: if not defaulthost: - if ADD_DEFAULT_STOREY: + if preferences['ADD_DEFAULT_STOREY']: defaulthost = ifcfile.createIfcBuildingStorey( ifcopenshell.guid.new(), history, @@ -986,9 +968,10 @@ def export(exportList,filename,colors=None): "ELEMENT", None ) - # if ADD_DEFAULT_STOREY is on, we need a building to host it, regardless of ADD_DEFAULT_BUILDING + # if preferences['ADD_DEFAULT_STOREY'] is on, we need a building + # to host it, regardless of preferences['ADD_DEFAULT_BUILDING'] if not buildings: - if DEBUG: print("No building found. Adding default building") + if preferences['DEBUG']: print("No building found. Adding default building") buildings = [ifcfile.createIfcBuilding( ifcopenshell.guid.new(), history, @@ -1041,7 +1024,7 @@ def export(exportList,filename,colors=None): ) else: # no default host: aggregate unassigned objects directly under the IfcProject - WARNING: NON STANDARD - if DEBUG: print("WARNING - Default building generation is disabled. You are producing a non-standard file.") + if preferences['DEBUG']: print("WARNING - Default building generation is disabled. You are producing a non-standard file.") ifcfile.createIfcRelAggregates( ifcopenshell.guid.new(), history, @@ -1098,9 +1081,9 @@ def export(exportList,filename,colors=None): # 2D objects annos = {} - if EXPORT_2D: + if preferences['EXPORT_2D']: curvestyles = {} - if annotations and DEBUG: print("exporting 2D objects...") + if annotations and preferences['DEBUG']: print("exporting 2D objects...") for anno in annotations: xvc = ifcbin.createIfcDirection((1.0,0.0,0.0)) zvc = ifcbin.createIfcDirection((0.0,0.0,1.0)) @@ -1253,7 +1236,7 @@ def export(exportList,filename,colors=None): remaining = [anno for anno in annos.values() if anno not in swallowed] if remaining: if not defaulthost: - if ADD_DEFAULT_STOREY: + if preferences['ADD_DEFAULT_STOREY']: defaulthost = ifcfile.createIfcBuildingStorey( ifcopenshell.guid.new(), history, @@ -1266,7 +1249,9 @@ def export(exportList,filename,colors=None): "ELEMENT", None ) - # if ADD_DEFAULT_STOREY is on, we need a building to host it, regardless of ADD_DEFAULT_BUILDING + # if preferences['ADD_DEFAULT_STOREY'] is on, we need a + # building to host it, regardless of + # preferences['ADD_DEFAULT_BUILDING'] if not buildings: buildings = [ifcfile.createIfcBuilding( ifcopenshell.guid.new(), @@ -1307,7 +1292,7 @@ def export(exportList,filename,colors=None): buildings[0], [defaulthost] ) - elif ADD_DEFAULT_BUILDING: + elif preferences['ADD_DEFAULT_BUILDING']: if not buildings: defaulthost = ifcfile.createIfcBuilding( ifcopenshell.guid.new(), @@ -1360,19 +1345,19 @@ def export(exportList,filename,colors=None): remaining ) - if DEBUG: print("writing ",filename,"...") + if preferences['DEBUG']: print("writing ",filename,"...") filename = decode(filename) ifcfile.write(filename) - if STORE_UID: + if preferences['STORE_UID']: # some properties might have been changed FreeCAD.ActiveDocument.recompute() os.remove(templatefile) - if DEBUG and ifcbin.compress: + if preferences['DEBUG'] and ifcbin.compress: f = pyopen(filename,"r") s = len(f.read().split("\n")) f.close() @@ -1383,7 +1368,7 @@ def export(exportList,filename,colors=None): # ************************************************************************************************ # ********** helper for export IFC ************** -def getPropertyData(key,value): +def getPropertyData(key,value,preferences): # in 0.18, properties in IfcProperties dict are stored as "key":"pset;;type;;value" or "key":"type;;value" # in 0.19, key = name;;pset, value = ptype;;value (because there can be several props with same name) @@ -1404,10 +1389,10 @@ def getPropertyData(key,value): ptype = value[0] pvalue = value[1] else: - if DEBUG:print(" unable to export property:",pname,value) + if preferences['DEBUG']:print(" unable to export property:",pname,value) return pset, pname, ptype, None - #if DEBUG: print(" property ",pname," : ",pvalue.encode("utf8"), " (", str(ptype), ") in ",pset) + #if preferences['DEBUG']: print(" property ",pname," : ",pvalue.encode("utf8"), " (", str(ptype), ") in ",pset) if ptype in ["IfcLabel","IfcText","IfcIdentifier",'IfcDescriptiveMeasure']: if six.PY2: pvalue = pvalue.encode("utf8") @@ -1432,7 +1417,7 @@ def getPropertyData(key,value): except: if six.PY2: pvalue = pvalue.encode("utf8") - if DEBUG:print(" warning: unable to export property as numeric value:",pname,pvalue) + if preferences['DEBUG']:print(" warning: unable to export property as numeric value:",pname,pvalue) # print('pset: {}, pname: {}, ptype: {}, pvalue: {}'.format(pset, pname, ptype, pvalue)) return pset, pname, ptype, pvalue @@ -1700,7 +1685,7 @@ def getProfile(ifcfile,p): return profile -def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tessellation=1,colors=None): +def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tessellation=1,colors=None,preferences=None): """returns an IfcShapeRepresentation object or None""" @@ -1857,7 +1842,7 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess from ifcopenshell import geom serialized = False - if hasattr(geom,"serialise") and obj.isDerivedFrom("Part::Feature") and SERIALIZE: + if hasattr(geom,"serialise") and obj.isDerivedFrom("Part::Feature") and preferences['SERIALIZE']: if obj.Shape.Faces: sh = obj.Shape.copy() sh.Placement = obj.getGlobalPlacement() @@ -1890,7 +1875,7 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess dataset = fcshape.Solids else: dataset = fcshape.Shells - #if DEBUG: print("Warning! object contains no solids") + #if preferences['DEBUG']: print("Warning! object contains no solids") for fcsolid in dataset: fcsolid.scale(0.001) # to meters diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index eea34da79f..90d91cf87d 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -192,7 +192,7 @@ def open(filename,skip=[],only=[],root=None): def insert(filename,docname,skip=[],only=[],root=None,preferences=None): - """insert(filename,docname,skip=[],only=[],root=None): imports the contents of an IFC file. + """insert(filename,docname,skip=[],only=[],root=None,preferences=None): imports the contents of an IFC file. skip can contain a list of ids of objects to be skipped, only can restrict the import to certain object ids (will also get their children) and root can be used to import only the derivates of a certain element type (default = ifcProduct).""" From 1e718010b9d66bc24b4c42a9e49d6431bca3d3ba Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 26 Aug 2019 14:01:15 -0300 Subject: [PATCH 6/8] Draft: Fixed regression in snapping --- src/Mod/Draft/DraftSnap.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 5445521bc8..d31a14d5cc 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -324,9 +324,14 @@ class Snapper: if (not self.maxEdges) or (len(shape.Edges) <= self.maxEdges): if "Edge" in comp: # we are snapping to an edge - en = int(comp[4:])-1 - if len(shape.Edges) > en: - edge = shape.Edges[en] + edge = None + if shape.ShapeType == "Edge": + edge = shape + else: + en = int(comp[4:])-1 + if len(shape.Edges) > en: + edge = shape.Edges[en] + if edge: snaps.extend(self.snapToEndpoints(edge)) snaps.extend(self.snapToMidpoint(edge)) snaps.extend(self.snapToPerpendicular(edge,lastpoint)) From f16f58c040691f99418830cf63074367e187ee0d Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 26 Aug 2019 14:16:19 -0300 Subject: [PATCH 7/8] Draft: Fixed tooltips --- src/Mod/Draft/DraftGui.py | 3 +++ src/Mod/Draft/DraftTools.py | 22 ++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 03d72e23f2..fb2c42deb6 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -1144,6 +1144,7 @@ class DraftToolBar: self.isCopy.setChecked(p.GetBool("OffsetCopyMode",False)) self.occOffset.show() self.labelRadius.setText(translate("draft","Distance")) + self.radiusValue.setToolTip(translate("draft", "Offset distance")) self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString) todo.delay(self.radiusValue.setFocus,None) self.radiusValue.selectAll() @@ -1214,6 +1215,7 @@ class DraftToolBar: self.taskUi(title) self.radiusUi() self.labelRadius.setText(translate("draft","Distance")) + self.radiusValue.setToolTip(translate("draft", "Trim distance")) self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString) todo.delay(self.radiusValue.setFocus,None) self.radiusValue.selectAll() @@ -1221,6 +1223,7 @@ class DraftToolBar: def radiusUi(self): self.hideXYZ() self.labelRadius.setText(translate("draft", "Radius")) + self.radiusValue.setToolTip(translate("draft", "Radius of Circle")) self.labelRadius.show() self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString) self.radiusValue.show() diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 831b51f966..7755ae9d62 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -1532,14 +1532,16 @@ class Arc(Creator): if self.closedCircle: self.drawArc() else: - self.ui.labelRadius.setText("Start angle") + self.ui.labelRadius.setText(translate("draft","Start angle")) + self.ui.radiusValue.setToolTip(translate("draft","Start angle")) self.ui.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Angle).UserString) self.linetrack.p1(self.center) self.linetrack.on() self.step = 2 FreeCAD.Console.PrintMessage(translate("draft", "Pick start angle")+"\n") elif (self.step == 2): # choose first angle - self.ui.labelRadius.setText("Aperture") + self.ui.labelRadius.setText(translate("draft","Aperture angle")) + self.ui.radiusValue.setToolTip(translate("draft","Aperture angle")) self.step = 3 # scale center->point vector for proper display # u = DraftVecUtils.scaleTo(self.point.sub(self.center), self.rad) obsolete? @@ -1649,14 +1651,16 @@ class Arc(Creator): else: self.step = 2 self.arctrack.setCenter(self.center) - self.ui.labelRadius.setText(translate("draft", "Start Angle")) + self.ui.labelRadius.setText(translate("draft", "Start angle")) + self.ui.radiusValue.setToolTip(translate("draft", "Start angle")) self.linetrack.p1(self.center) self.linetrack.on() self.ui.radiusValue.setText("") self.ui.radiusValue.setFocus() FreeCAD.Console.PrintMessage(translate("draft", "Pick start angle")+"\n") elif (self.step == 2): - self.ui.labelRadius.setText(translate("draft", "Aperture")) + self.ui.labelRadius.setText(translate("draft", "Aperture angle")) + self.ui.radiusValue.setToolTip(translate("draft", "Aperture angle")) self.firstangle = math.radians(rad) if DraftVecUtils.equals(plane.axis, Vector(1,0,0)): u = Vector(0,self.rad,0) else: u = DraftVecUtils.scaleTo(Vector(1,0,0).cross(plane.axis), self.rad) @@ -2892,6 +2896,7 @@ class Rotate(Modifier): self.ui.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Angle).UserString) self.ui.hasFill.hide() self.ui.labelRadius.setText(translate("draft","Base angle")) + self.ui.radiusValue.setToolTip(translate("draft","The base angle you wish to start the rotation from")) self.arctrack.setCenter(self.center) for ghost in self.ghosts: ghost.center(self.center) @@ -2902,6 +2907,7 @@ class Rotate(Modifier): def set_start_point(self): self.ui.labelRadius.setText(translate("draft","Rotation")) + self.ui.radiusValue.setToolTip(translate("draft", "The amount of rotation you wish to perform. The final angle will be the base angle plus this amount.")) self.rad = DraftVecUtils.dist(self.point,self.center) self.arctrack.on() self.arctrack.setStartPoint(self.point) @@ -3029,6 +3035,7 @@ class Rotate(Modifier): self.ui.radiusUi() self.ui.hasFill.hide() self.ui.labelRadius.setText(translate("draft","Base angle")) + self.ui.radiusValue.setToolTip(translate("draft","The base angle you wish to start the rotation from")) self.step = 1 FreeCAD.Console.PrintMessage(translate("draft", "Pick base angle")+"\n") @@ -3036,6 +3043,7 @@ class Rotate(Modifier): """this function gets called by the toolbar when valid radius have been entered there""" if (self.step == 1): self.ui.labelRadius.setText(translate("draft","Rotation")) + self.ui.radiusValue.setToolTip(translate("draft","The amount of rotation you wish to perform. The final angle will be the base angle plus this amount.")) self.firstangle = math.radians(rad) self.arctrack.setStartAngle(self.firstangle) self.arctrack.on() @@ -3904,7 +3912,8 @@ class Trimex(Modifier): dist = v1.sub(self.newpoint).Length ghost.p1(self.newpoint) ghost.p2(v2) - self.ui.labelRadius.setText("Distance") + self.ui.labelRadius.setText(translate("draft","Distance")) + self.ui.radiusValue.setToolTip(translate("draft", "The offset distance")) if real: if self.force: ray = self.newpoint.sub(v1) @@ -3917,7 +3926,8 @@ class Trimex(Modifier): ang1 = DraftVecUtils.angle(v2.sub(center)) ang2 = DraftVecUtils.angle(point.sub(center)) self.newpoint=Vector.add(center,DraftVecUtils.rotate(Vector(rad,0,0),-ang2)) - self.ui.labelRadius.setText("Angle") + self.ui.labelRadius.setText(translate("draft","Angle")) + self.ui.radiusValue.setToolTip(translate("draft", "The offset angle")) dist = math.degrees(-ang2) # if ang1 > ang2: ang1,ang2 = ang2,ang1 #print("last calculated:",math.degrees(-ang1),math.degrees(-ang2)) From 9cd5a7ee5eb71897cbb339307159b569ce713b97 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 26 Aug 2019 15:39:22 -0300 Subject: [PATCH 8/8] Arch: Solved bug in Structure --- src/Mod/Arch/ArchIFC.py | 5 +++-- src/Mod/Arch/ArchStructure.py | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Mod/Arch/ArchIFC.py b/src/Mod/Arch/ArchIFC.py index d5b2616dde..87c6737a40 100644 --- a/src/Mod/Arch/ArchIFC.py +++ b/src/Mod/Arch/ArchIFC.py @@ -30,8 +30,9 @@ class IfcRoot: if prop == "IfcType": self.setupIfcAttributes(obj) self.setupIfcComplexAttributes(obj) - if obj.getGroupOfProperty(prop) == "IFC Attributes": - self.setObjIfcAttributeValue(obj, prop, obj.getPropertyByName(prop)) + if prop in obj.PropertiesList: + if obj.getGroupOfProperty(prop) == "IFC Attributes": + self.setObjIfcAttributeValue(obj, prop, obj.getPropertyByName(prop)) def setupIfcAttributes(self, obj): ifcTypeSchema = self.getIfcTypeSchema(obj.IfcType) diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py index 051993977f..b18c787005 100644 --- a/src/Mod/Arch/ArchStructure.py +++ b/src/Mod/Arch/ArchStructure.py @@ -947,12 +947,12 @@ class _ViewProviderStructure(ArchComponent.ViewProviderComponent): p.append([n.x,n.y,n.z]) self.coords.point.setValues(0,len(p),p) self.pointset.numPoints.setValue(len(p)) - self.lineset.coordIndex.setValues(0,len(p)+1,range(len(p))+[-1]) + self.lineset.coordIndex.setValues(0,len(p)+1,list(range(len(p)))+[-1]) if hasattr(obj.ViewObject,"NodeType"): if (obj.ViewObject.NodeType == "Area") and (len(p) > 2): self.coords.point.set1Value(len(p),p[0][0],p[0][1],p[0][2]) - self.lineset.coordIndex.setValues(0,len(p)+2,range(len(p)+1)+[-1]) - self.faceset.coordIndex.setValues(0,len(p)+1,range(len(p))+[-1]) + self.lineset.coordIndex.setValues(0,len(p)+2,list(range(len(p)+1))+[-1]) + self.faceset.coordIndex.setValues(0,len(p)+1,list(range(len(p)))+[-1]) elif prop in ["IfcType"]: if hasattr(obj.ViewObject,"NodeType"):