Merge branch 'master' into master
This commit is contained in:
@@ -1889,7 +1889,7 @@ void Application::initConfig(int argc, char ** argv)
|
||||
Branding brand;
|
||||
QString binDir = QString::fromUtf8((mConfig["AppHomePath"] + "bin").c_str());
|
||||
QFileInfo fi(binDir, QString::fromLatin1("branding.xml"));
|
||||
if (brand.readFile(fi.absoluteFilePath())) {
|
||||
if (fi.exists() && brand.readFile(fi.absoluteFilePath())) {
|
||||
Branding::XmlConfig cfg = brand.getUserDefines();
|
||||
for (Branding::XmlConfig::iterator it = cfg.begin(); it != cfg.end(); ++it) {
|
||||
App::Application::Config()[it.key()] = it.value();
|
||||
|
||||
@@ -126,8 +126,6 @@ ConsoleSingleton::ConsoleSingleton(void)
|
||||
,_defaultLogLevel(FC_LOGLEVEL_MSG)
|
||||
#endif
|
||||
{
|
||||
// make sure this object is part of the main thread
|
||||
ConsoleOutput::getInstance();
|
||||
}
|
||||
|
||||
ConsoleSingleton::~ConsoleSingleton()
|
||||
@@ -233,6 +231,11 @@ bool ConsoleSingleton::IsMsgTypeEnabled(const char* sObs, FreeCAD_ConsoleMsgType
|
||||
void ConsoleSingleton::SetConnectionMode(ConnectionMode mode)
|
||||
{
|
||||
connectionMode = mode;
|
||||
|
||||
// make sure this method gets called from the main thread
|
||||
if (connectionMode == Queued) {
|
||||
ConsoleOutput::getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prints a Message
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "PreCompiled.h"
|
||||
#include "PyExport.h"
|
||||
#include "Exception.h"
|
||||
#include <sstream>
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-register"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "PreCompiled.h"
|
||||
#include "PyExport.h"
|
||||
#include "Exception.h"
|
||||
#include <sstream>
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-register"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "PreCompiled.h"
|
||||
#include "PyExport.h"
|
||||
#include "Exception.h"
|
||||
#include <sstream>
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-register"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "PreCompiled.h"
|
||||
#include "PyExport.h"
|
||||
#include "Exception.h"
|
||||
#include <sstream>
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-register"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "PreCompiled.h"
|
||||
#include "PyExport.h"
|
||||
#include "Exception.h"
|
||||
#include <sstream>
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-register"
|
||||
|
||||
@@ -147,14 +147,17 @@ namespace Gui {
|
||||
// Pimpl class
|
||||
struct ApplicationP
|
||||
{
|
||||
ApplicationP() :
|
||||
ApplicationP(bool GUIenabled) :
|
||||
activeDocument(0L),
|
||||
editDocument(0L),
|
||||
isClosing(false),
|
||||
startingUp(true)
|
||||
{
|
||||
// create the macro manager
|
||||
macroMngr = new MacroManager();
|
||||
if (GUIenabled)
|
||||
macroMngr = new MacroManager();
|
||||
else
|
||||
macroMngr = nullptr;
|
||||
}
|
||||
|
||||
~ApplicationP()
|
||||
@@ -227,6 +230,47 @@ FreeCADGui_subgraphFromObject(PyObject * /*self*/, PyObject *args)
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
FreeCADGui_replaceSwitchNodes(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject* proxy;
|
||||
if (!PyArg_ParseTuple(args, "O", &proxy))
|
||||
return nullptr;
|
||||
|
||||
void* ptr = 0;
|
||||
try {
|
||||
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoNode *", proxy, &ptr, 0);
|
||||
SoNode* node = reinterpret_cast<SoNode*>(ptr);
|
||||
SoNode* replace = SoFCDB::replaceSwitches(node);
|
||||
if (replace) {
|
||||
replace->ref();
|
||||
|
||||
std::string prefix = "So";
|
||||
std::string type = replace->getTypeId().getName().getString();
|
||||
// doesn't start with the prefix 'So'
|
||||
if (type.rfind("So", 0) != 0) {
|
||||
type = prefix + type;
|
||||
}
|
||||
else if (type == "SoFCSelectionRoot") {
|
||||
type = "SoSeparator";
|
||||
}
|
||||
|
||||
type += " *";
|
||||
PyObject* proxy = 0;
|
||||
proxy = Base::Interpreter().createSWIGPointerObj("pivy.coin", type.c_str(), (void*)replace, 1);
|
||||
return Py::new_reference_to(Py::Object(proxy, true));
|
||||
}
|
||||
else {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
PyErr_SetString(PyExc_RuntimeError, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
FreeCADGui_getSoDBVersion(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
@@ -290,6 +334,9 @@ struct PyMethodDef FreeCADGui_methods[] = {
|
||||
{"subgraphFromObject",FreeCADGui_subgraphFromObject,METH_VARARGS,
|
||||
"subgraphFromObject(object) -> Node\n\n"
|
||||
"Return the Inventor subgraph to an object"},
|
||||
{"replaceSwitchNodes",FreeCADGui_replaceSwitchNodes,METH_VARARGS,
|
||||
"replaceSwitchNodes(Node) -> Node\n\n"
|
||||
"Replace Switch nodes with Separators"},
|
||||
{"getSoDBVersion",FreeCADGui_getSoDBVersion,METH_VARARGS,
|
||||
"getSoDBVersion() -> String\n\n"
|
||||
"Return a text string containing the name\n"
|
||||
@@ -451,7 +498,7 @@ Application::Application(bool GUIenabled)
|
||||
View3DInventorViewerPy ::init_type();
|
||||
AbstractSplitViewPy ::init_type();
|
||||
|
||||
d = new ApplicationP;
|
||||
d = new ApplicationP(GUIenabled);
|
||||
|
||||
// global access
|
||||
Instance = this;
|
||||
|
||||
@@ -295,6 +295,11 @@ SoNode* replaceSwitchesInSceneGraph(SoNode* node)
|
||||
return node;
|
||||
}
|
||||
|
||||
SoNode* Gui::SoFCDB::replaceSwitches(SoNode* node)
|
||||
{
|
||||
return replaceSwitchesInSceneGraph(node);
|
||||
}
|
||||
|
||||
bool Gui::SoFCDB::writeToVRML(SoNode* node, const char* filename, bool binary)
|
||||
{
|
||||
SoNode* noSwitches = replaceSwitchesInSceneGraph(node);
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
static SbBool isInitialized(void);
|
||||
static void init();
|
||||
static void finish();
|
||||
static SoNode* replaceSwitches(SoNode* node);
|
||||
/// helper to apply a SoWriteAction to a node and write it to a string
|
||||
static const std::string& writeNodesToString(SoNode * root);
|
||||
static bool writeToVRML(SoNode* node, const char* filename, bool binary);
|
||||
|
||||
@@ -52,10 +52,30 @@
|
||||
#include <Gui/SoFCDB.h>
|
||||
#include <Gui/Quarter/Quarter.h>
|
||||
#include <Inventor/SoDB.h>
|
||||
#include <Inventor/SoInteraction.h>
|
||||
#include <Inventor/nodekits/SoNodeKit.h>
|
||||
|
||||
static bool _isSetupWithoutGui = false;
|
||||
|
||||
static
|
||||
QWidget* setupMainWindow();
|
||||
|
||||
class QtApplication : public QApplication {
|
||||
public:
|
||||
QtApplication(int &argc, char **argv)
|
||||
: QApplication(argc, argv) {
|
||||
}
|
||||
bool notify (QObject * receiver, QEvent * event) {
|
||||
try {
|
||||
return QApplication::notify(receiver, event);
|
||||
}
|
||||
catch (const Base::SystemExitException& e) {
|
||||
exit(e.getExitCode());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
HHOOK hhook;
|
||||
|
||||
@@ -70,6 +90,11 @@ FilterProc(int nCode, WPARAM wParam, LPARAM lParam) {
|
||||
static PyObject *
|
||||
FreeCADGui_showMainWindow(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
if (_isSetupWithoutGui) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Cannot call showMainWindow() after calling setupWithoutGUI()\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyObject* inThread = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &inThread))
|
||||
return NULL;
|
||||
@@ -84,7 +109,10 @@ FreeCADGui_showMainWindow(PyObject * /*self*/, PyObject *args)
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||
#endif
|
||||
QApplication app(argc, argv);
|
||||
// This only works well if the QApplication is the very first created instance
|
||||
// of a QObject. Otherwise the application lives in a different thread than the
|
||||
// main thread which will cause hazardous behaviour.
|
||||
QtApplication app(argc, argv);
|
||||
if (setupMainWindow()) {
|
||||
app.exec();
|
||||
}
|
||||
@@ -92,6 +120,9 @@ FreeCADGui_showMainWindow(PyObject * /*self*/, PyObject *args)
|
||||
t.detach();
|
||||
}
|
||||
else {
|
||||
// In order to get Jupiter notebook integration working we must create a direct instance
|
||||
// of QApplication. Not even a sub-class can be used because otherwise PySide2 wraps it
|
||||
// with a QtCore.QCoreApplication which will raise an exception in ipykernel
|
||||
#if defined(Q_OS_WIN)
|
||||
static int argc = 0;
|
||||
static char **argv = {0};
|
||||
@@ -154,6 +185,7 @@ FreeCADGui_setupWithoutGUI(PyObject * /*self*/, PyObject *args)
|
||||
|
||||
if (!Gui::Application::Instance) {
|
||||
static Gui::Application *app = new Gui::Application(false);
|
||||
_isSetupWithoutGui = true;
|
||||
Q_UNUSED(app);
|
||||
}
|
||||
else {
|
||||
@@ -164,7 +196,8 @@ FreeCADGui_setupWithoutGUI(PyObject * /*self*/, PyObject *args)
|
||||
if (!SoDB::isInitialized()) {
|
||||
// init the Inventor subsystem
|
||||
SoDB::init();
|
||||
SIM::Coin3D::Quarter::Quarter::init();
|
||||
SoNodeKit::init();
|
||||
SoInteraction::init();
|
||||
}
|
||||
if (!Gui::SoFCDB::isInitialized()) {
|
||||
Gui::SoFCDB::init();
|
||||
|
||||
@@ -67,6 +67,9 @@
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="geo1Reference">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -77,7 +80,7 @@
|
||||
<string><html><head/><body><p>Choose what point to use on the first selected feature.</p></body></html></string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
@@ -159,7 +162,7 @@
|
||||
<string><html><head/><body><p>Choose what point to use on the second selected feature.</p></body></html></string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
|
||||
@@ -46,8 +46,12 @@ Part = LazyLoader('Part', globals(), 'Part')
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
DEBUG = False
|
||||
if DEBUG:
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
|
||||
PathLog.trackModule(PathLog.thisModule())
|
||||
else:
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
@@ -91,6 +95,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
# Set enumeration lists for enumeration properties
|
||||
if len(self.addNewProps) > 0:
|
||||
ENUMS = self.opPropertyEnumerations()
|
||||
# ENUMS = self.getActiveEnumerations(obj)
|
||||
for n in ENUMS:
|
||||
if n in self.addNewProps:
|
||||
setattr(obj, n, ENUMS[n])
|
||||
@@ -114,6 +119,8 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Enter custom start point for slot path.")),
|
||||
("App::PropertyVectorDistance", "CustomPoint2", "Slot",
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Enter custom end point for slot path.")),
|
||||
("App::PropertyEnumeration", "CutPattern", "Slot",
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Set the geometric clearing pattern to use for the operation.")),
|
||||
("App::PropertyDistance", "ExtendPathStart", "Slot",
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Positive extends the beginning of the path, negative shortens.")),
|
||||
("App::PropertyDistance", "ExtendPathEnd", "Slot",
|
||||
@@ -138,6 +145,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
def opPropertyEnumerations(self):
|
||||
# Enumeration lists for App::PropertyEnumeration properties
|
||||
return {
|
||||
'CutPattern': ['Line', 'ZigZag'],
|
||||
'LayerMode': ['Single-pass', 'Multi-pass'],
|
||||
'PathOrientation': ['Start to End', 'Perpendicular'],
|
||||
'Reference1': ['Center of Mass', 'Center of BoundBox',
|
||||
@@ -157,7 +165,8 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
'CustomPoint2': FreeCAD.Vector(10.0, 10.0, 0.0),
|
||||
'ExtendPathEnd': 0.0,
|
||||
'Reference2': 'Center of Mass',
|
||||
'LayerMode': 'Single-pass',
|
||||
'LayerMode': 'Multi-pass',
|
||||
'CutPattern': 'ZigZag',
|
||||
'PathOrientation': 'Start to End',
|
||||
'ReverseDirection': False,
|
||||
|
||||
@@ -167,27 +176,64 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
return defaults
|
||||
|
||||
def setEditorProperties(self, obj):
|
||||
# Used to hide inputs in properties list
|
||||
A = B = 2
|
||||
def getActiveEnumerations(self, obj):
|
||||
"""getActiveEnumerations(obj) ...
|
||||
Method returns dictionary of property enumerations based on
|
||||
active conditions in the operation."""
|
||||
ENUMS = self.opPropertyEnumerations()
|
||||
if hasattr(obj, 'Base'):
|
||||
enums2 = self.opPropertyEnumerations()['Reference2']
|
||||
if obj.Base:
|
||||
(base, subsList) = obj.Base[0]
|
||||
subCnt = len(subsList)
|
||||
if subCnt == 1:
|
||||
# Adjust available enumerations
|
||||
obj.Reference1 = self._getReference1Enums(subsList[0], True)
|
||||
A = 0
|
||||
ENUMS['Reference1'] = self._makeReference1Enumerations(subsList[0], True)
|
||||
elif subCnt == 2:
|
||||
# Adjust available enumerations
|
||||
obj.Reference1 = self._getReference1Enums(subsList[0])
|
||||
obj.Reference2 = self._getReference2Enums(subsList[1])
|
||||
ENUMS['Reference1'] = self._makeReference1Enumerations(subsList[0])
|
||||
ENUMS['Reference2'] = self._makeReference2Enumerations(subsList[1])
|
||||
return ENUMS
|
||||
|
||||
def updateEnumerations(self, obj):
|
||||
"""updateEnumerations(obj) ...
|
||||
Method updates property enumerations based on active conditions
|
||||
in the operation. Returns the updated enumerations dictionary.
|
||||
Existing property values must be stored, and then restored after
|
||||
the assignment of updated enumerations."""
|
||||
PathLog.debug('updateEnumerations()')
|
||||
# Save existing values
|
||||
pre_Ref1 = obj.Reference1
|
||||
pre_Ref2 = obj.Reference2
|
||||
|
||||
# Update enumerations
|
||||
ENUMS = self.getActiveEnumerations(obj)
|
||||
obj.Reference1 = ENUMS['Reference1']
|
||||
obj.Reference2 = ENUMS['Reference2']
|
||||
|
||||
# Restore pre-existing values if available with active enumerations.
|
||||
# If not, set to first element in active enumeration list.
|
||||
if pre_Ref1 in ENUMS['Reference1']:
|
||||
obj.Reference1 = pre_Ref1
|
||||
else:
|
||||
obj.Reference1 = ENUMS['Reference1'][0]
|
||||
if pre_Ref2 in ENUMS['Reference2']:
|
||||
obj.Reference2 = pre_Ref2
|
||||
else:
|
||||
obj.Reference2 = ENUMS['Reference2'][0]
|
||||
|
||||
return ENUMS
|
||||
|
||||
def setEditorProperties(self, obj):
|
||||
# Used to hide inputs in properties list
|
||||
A = B = 2
|
||||
if hasattr(obj, 'Base'):
|
||||
if obj.Base:
|
||||
(base, subsList) = obj.Base[0]
|
||||
subCnt = len(subsList)
|
||||
if subCnt == 1:
|
||||
A = 0
|
||||
elif subCnt == 2:
|
||||
A = B = 0
|
||||
else:
|
||||
ENUMS = self.opPropertyEnumerations()
|
||||
obj.Reference1 = ENUMS['Reference1']
|
||||
obj.Reference2 = ENUMS['Reference2']
|
||||
|
||||
obj.setEditorMode('Reference1', A)
|
||||
obj.setEditorMode('Reference2', B)
|
||||
@@ -196,6 +242,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
if hasattr(self, 'propertiesReady'):
|
||||
if self.propertiesReady:
|
||||
if prop in ['Base']:
|
||||
self.updateEnumerations(obj)
|
||||
self.setEditorProperties(obj)
|
||||
|
||||
def opOnDocumentRestored(self, obj):
|
||||
@@ -209,15 +256,15 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
obj.setEditorMode('ShowTempObjects', mode)
|
||||
|
||||
# Repopulate enumerations in case of changes
|
||||
ENUMS = self.opPropertyEnumerations()
|
||||
ENUMS = self.updateEnumerations(obj)
|
||||
for n in ENUMS:
|
||||
restore = False
|
||||
if hasattr(obj, n):
|
||||
val = obj.getPropertyByName(n)
|
||||
restore = True
|
||||
setattr(obj, n, ENUMS[n])
|
||||
setattr(obj, n, ENUMS[n]) # set the enumerations list
|
||||
if restore:
|
||||
setattr(obj, n, val)
|
||||
setattr(obj, n, val) # restore the value
|
||||
|
||||
self.setEditorProperties(obj)
|
||||
|
||||
@@ -320,6 +367,8 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
self.tmpGrp = FreeCAD.ActiveDocument.addObject('App::DocumentObjectGroup', 'tmpDebugGrp')
|
||||
tmpGrpNm = self.tmpGrp.Name
|
||||
|
||||
# self.updateEnumerations(obj)
|
||||
|
||||
# Identify parent Job
|
||||
JOB = PathUtils.findParentJob(obj)
|
||||
self.JOB = JOB
|
||||
@@ -418,11 +467,14 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
lenSL = len(subsList)
|
||||
featureCnt = lenSL
|
||||
if lenSL == 1:
|
||||
PathLog.debug('Reference 1: {}'.format(obj.Reference1))
|
||||
sub1 = subsList[0]
|
||||
shape_1 = getattr(base.Shape, sub1)
|
||||
self.shape1 = shape_1
|
||||
pnts = self._processSingle(obj, shape_1, sub1)
|
||||
else:
|
||||
PathLog.debug('Reference 1: {}'.format(obj.Reference1))
|
||||
PathLog.debug('Reference 2: {}'.format(obj.Reference2))
|
||||
sub1 = subsList[0]
|
||||
sub2 = subsList[1]
|
||||
shape_1 = getattr(base.Shape, sub1)
|
||||
@@ -467,7 +519,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
(p1, p2) = pnts
|
||||
if self.isDebug:
|
||||
PathLog.debug('p1, p2: {}, {}'.format(p1, p2))
|
||||
PathLog.debug('Path Points are:\np1 = {}\np2 = {}'.format(p1, p2))
|
||||
if p1.sub(p2).Length != 0 and self.showTempObjects:
|
||||
O = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmp_Path')
|
||||
O.Shape = Part.makeLine(p1, p2)
|
||||
@@ -493,7 +545,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
It returns the slot gcode for the operation."""
|
||||
CMDS = list()
|
||||
|
||||
def layerPass(p1, p2, depth):
|
||||
def linePass(p1, p2, depth):
|
||||
cmds = list()
|
||||
# cmds.append(Path.Command('N (Tool type: {})'.format(toolType), {}))
|
||||
cmds.append(Path.Command('G0', {'X': p1.x, 'Y': p1.y, 'F': self.horizRapid}))
|
||||
@@ -502,16 +554,25 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
return cmds
|
||||
|
||||
# CMDS.append(Path.Command('N (Tool type: {})'.format(toolType), {}))
|
||||
# CMDS.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
|
||||
if obj.LayerMode == 'Single-pass':
|
||||
CMDS.extend(layerPass(p1, p2, obj.FinalDepth.Value))
|
||||
CMDS.extend(linePass(p1, p2, obj.FinalDepth.Value))
|
||||
CMDS.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
|
||||
else:
|
||||
prvDep = obj.StartDepth.Value
|
||||
for dep in self.depthParams:
|
||||
CMDS.extend(layerPass(p1, p2, dep))
|
||||
CMDS.append(Path.Command('G0', {'Z': prvDep, 'F': self.vertRapid}))
|
||||
prvDep = dep
|
||||
if obj.CutPattern == 'Line':
|
||||
for dep in self.depthParams:
|
||||
CMDS.extend(linePass(p1, p2, dep))
|
||||
CMDS.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
|
||||
elif obj.CutPattern == 'ZigZag':
|
||||
CMDS.append(Path.Command('G0', {'X': p1.x, 'Y': p1.y, 'F': self.horizRapid}))
|
||||
i = 0
|
||||
for dep in self.depthParams:
|
||||
if i % 2.0 == 0: # even
|
||||
CMDS.append(Path.Command('G1', {'Z': dep, 'F': self.vertFeed}))
|
||||
CMDS.append(Path.Command('G1', {'X': p2.x, 'Y': p2.y, 'F': self.horizFeed}))
|
||||
else: # odd
|
||||
CMDS.append(Path.Command('G1', {'Z': dep, 'F': self.vertFeed}))
|
||||
CMDS.append(Path.Command('G1', {'X': p1.x, 'Y': p1.y, 'F': self.horizFeed}))
|
||||
i += 1
|
||||
CMDS.append(Path.Command('G0', {'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
|
||||
|
||||
return CMDS
|
||||
@@ -528,7 +589,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
pnts = False
|
||||
|
||||
norm = shape_1.normalAt(0.0, 0.0)
|
||||
PathLog.debug('Face.normalAt(): {}'.format(norm))
|
||||
PathLog.debug('{}.normalAt(): {}'.format(sub1, norm))
|
||||
if norm.z == 1 or norm.z == -1:
|
||||
pnts = self._processSingleHorizFace(obj, shape_1)
|
||||
elif norm.z == 0:
|
||||
@@ -571,6 +632,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
def _processSingleHorizFace(self, obj, shape):
|
||||
"""Determine slot path endpoints from a single horizontally oriented face."""
|
||||
PathLog.debug('_processSingleHorizFace()')
|
||||
lineTypes = ['Part::GeomLine']
|
||||
|
||||
def getRadians(self, E):
|
||||
@@ -603,8 +665,6 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
pairs = list()
|
||||
eCnt = len(shape.Edges)
|
||||
lstE = eCnt - 1
|
||||
I = [i for i in range(0, eCnt)]
|
||||
I.append(0)
|
||||
for i in range(0, eCnt):
|
||||
if i < lstE:
|
||||
ni = i + 1
|
||||
@@ -629,6 +689,11 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
if pairCnt > 1:
|
||||
pairs.sort(key=lambda tup: tup[0].Length, reverse=True)
|
||||
|
||||
if self.isDebug:
|
||||
PathLog.debug(' -pairCnt: {}'.format(pairCnt))
|
||||
for (a, b) in pairs:
|
||||
PathLog.debug(' -pair: {}, {}'.format(round(a.Length, 4), round(b.Length,4)))
|
||||
|
||||
if pairCnt == 0:
|
||||
msg = translate('PathSlot',
|
||||
'No parallel edges identified.')
|
||||
@@ -638,9 +703,9 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
same = pairs[0]
|
||||
else:
|
||||
if obj.Reference1 == 'Long Edge':
|
||||
same = pairs[0]
|
||||
elif obj.Reference1 == 'Short Edge':
|
||||
same = pairs[1]
|
||||
elif obj.Reference1 == 'Short Edge':
|
||||
same = pairs[0]
|
||||
else:
|
||||
msg = 'Reference1 '
|
||||
msg += translate('PathSlot',
|
||||
@@ -653,6 +718,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
def _processSingleComplexFace(self, obj, shape):
|
||||
"""Determine slot path endpoints from a single complex face."""
|
||||
PathLog.debug('_processSingleComplexFace()')
|
||||
PNTS = list()
|
||||
|
||||
def zVal(V):
|
||||
@@ -667,6 +733,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
def _processSingleVertFace(self, obj, shape):
|
||||
"""Determine slot path endpoints from a single vertically oriented face
|
||||
with no single bottom edge."""
|
||||
PathLog.debug('_processSingleVertFace()')
|
||||
eCnt = len(shape.Edges)
|
||||
V0 = shape.Edges[0].Vertexes[0]
|
||||
V1 = shape.Edges[eCnt - 1].Vertexes[1]
|
||||
@@ -691,6 +758,7 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
# Methods for processing double geometry
|
||||
def _processDouble(self, obj, shape_1, sub1, shape_2, sub2):
|
||||
PathLog.debug('_processDouble()')
|
||||
"""This is the control method for slots based on a
|
||||
two Base Geometry features."""
|
||||
cmds = False
|
||||
@@ -898,47 +966,12 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
n2 = p2
|
||||
return (n1, n2)
|
||||
|
||||
def _getEndMidPoints(self, same):
|
||||
# Find mid-points between ends of equal, oppossing edges
|
||||
e0va = same[0].Vertexes[0]
|
||||
e0vb = same[0].Vertexes[1]
|
||||
e1va = same[1].Vertexes[0]
|
||||
e1vb = same[1].Vertexes[1]
|
||||
|
||||
if False:
|
||||
midX1 = (e0va.X + e0vb.X) / 2.0
|
||||
midY1 = (e0va.Y + e0vb.Y) / 2.0
|
||||
midX2 = (e1va.X + e1vb.X) / 2.0
|
||||
midY2 = (e1va.Y + e1vb.Y) / 2.0
|
||||
m1 = FreeCAD.Vector(midX1, midY1, e0va.Z)
|
||||
m2 = FreeCAD.Vector(midX2, midY2, e0va.Z)
|
||||
|
||||
p1 = FreeCAD.Vector(e0va.X, e0va.Y, e0va.Z)
|
||||
p2 = FreeCAD.Vector(e0vb.X, e0vb.Y, e0vb.Z)
|
||||
p3 = FreeCAD.Vector(e1va.X, e1va.Y, e1va.Z)
|
||||
p4 = FreeCAD.Vector(e1vb.X, e1vb.Y, e1vb.Z)
|
||||
|
||||
L0 = Part.makeLine(p1, p2)
|
||||
L1 = Part.makeLine(p3, p4)
|
||||
comL0 = L0.CenterOfMass
|
||||
comL1 = L1.CenterOfMass
|
||||
m1 = FreeCAD.Vector(comL0.x, comL0.y, 0.0)
|
||||
m2 = FreeCAD.Vector(comL1.x, comL1.y, 0.0)
|
||||
|
||||
return (m1, m2)
|
||||
|
||||
def _getOppMidPoints(self, same):
|
||||
# Find mid-points between ends of equal, oppossing edges
|
||||
v1 = same[0].Vertexes[0]
|
||||
v2 = same[0].Vertexes[1]
|
||||
a1 = same[1].Vertexes[0]
|
||||
a2 = same[1].Vertexes[1]
|
||||
midX1 = (v1.X + a2.X) / 2.0
|
||||
midY1 = (v1.Y + a2.Y) / 2.0
|
||||
midX2 = (v2.X + a1.X) / 2.0
|
||||
midY2 = (v2.Y + a1.Y) / 2.0
|
||||
p1 = FreeCAD.Vector(midX1, midY1, v1.Z)
|
||||
p2 = FreeCAD.Vector(midX2, midY2, v1.Z)
|
||||
com1 = same[0].CenterOfMass
|
||||
com2 = same[1].CenterOfMass
|
||||
p1 = FreeCAD.Vector(com1.x, com1.y, 0.0)
|
||||
p2 = FreeCAD.Vector(com2.x, com2.y, 0.0)
|
||||
return (p1, p2)
|
||||
|
||||
def _isParallel(self, dYdX1, dYdX2):
|
||||
@@ -1152,19 +1185,31 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
return ('Wire', wires[0])
|
||||
return False
|
||||
|
||||
def _getReference1Enums(self, sub, single=False):
|
||||
# Adjust available enumerations
|
||||
enums1 = self.opPropertyEnumerations()['Reference1']
|
||||
for ri in removeIndexesFromReference_1(sub, single):
|
||||
enums1.pop(ri)
|
||||
return enums1
|
||||
def _makeReference1Enumerations(self, sub, single=False):
|
||||
"""Customize Reference1 enumerations based on feature type."""
|
||||
PathLog.debug('_makeReference1Enumerations()')
|
||||
cat = sub[:4]
|
||||
if single:
|
||||
if cat == 'Face':
|
||||
return ['Long Edge', 'Short Edge']
|
||||
elif cat == 'Edge':
|
||||
return ['Long Edge']
|
||||
elif cat == 'Vert':
|
||||
return ['Vertex']
|
||||
elif cat == 'Vert':
|
||||
return ['Vertex']
|
||||
|
||||
def _getReference2Enums(self, sub):
|
||||
# Adjust available enumerations
|
||||
enums2 = self.opPropertyEnumerations()['Reference2']
|
||||
for ri in removeIndexesFromReference_2(sub):
|
||||
enums2.pop(ri)
|
||||
return enums2
|
||||
return ['Center of Mass', 'Center of BoundBox',
|
||||
'Lowest Point', 'Highest Point']
|
||||
|
||||
def _makeReference2Enumerations(self, sub):
|
||||
"""Customize Reference2 enumerations based on feature type."""
|
||||
PathLog.debug('_makeReference2Enumerations()')
|
||||
cat = sub[:4]
|
||||
if cat == 'Vert':
|
||||
return ['Vertex']
|
||||
return ['Center of Mass', 'Center of BoundBox',
|
||||
'Lowest Point', 'Highest Point']
|
||||
|
||||
def _lineCollisionCheck(self, obj, p1, p2):
|
||||
"""Make simple circle with diameter of tool, at start point.
|
||||
@@ -1176,44 +1221,51 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
|
||||
def getPerp(p1, p2, dist):
|
||||
toEnd = p2.sub(p1)
|
||||
factor = dist / toEnd.Length
|
||||
perp = FreeCAD.Vector(-1 * toEnd.y, toEnd.x, 0.0)
|
||||
if perp.x == 0 and perp.y == 0:
|
||||
return perp
|
||||
perp.normalize()
|
||||
perp.multiply(dist)
|
||||
return perp
|
||||
|
||||
# Make first cylinder
|
||||
ce1 = Part.Wire(Part.makeCircle(rad, p1).Edges)
|
||||
ce2 = Part.Wire(Part.makeCircle(rad, p2).Edges)
|
||||
C1 = Part.Face(ce1)
|
||||
C2 = Part.Face(ce2)
|
||||
|
||||
zTrans = obj.FinalDepth.Value - C1.BoundBox.ZMin
|
||||
C1.translate(FreeCAD.Vector(0.0, 0.0, zTrans))
|
||||
zTrans = obj.FinalDepth.Value - C2.BoundBox.ZMin
|
||||
C2.translate(FreeCAD.Vector(0.0, 0.0, zTrans))
|
||||
|
||||
extFwd = obj.StartDepth.Value - obj.FinalDepth.Value
|
||||
extVect = FreeCAD.Vector(0.0, 0.0, extFwd)
|
||||
startShp = C1.extrude(extVect)
|
||||
endShp = C2.extrude(extVect)
|
||||
|
||||
perp = getPerp(p1, p2, rad)
|
||||
v1 = p1.add(perp)
|
||||
v2 = p1.sub(perp)
|
||||
v3 = p2.sub(perp)
|
||||
v4 = p2.add(perp)
|
||||
e1 = Part.makeLine(v1, v2)
|
||||
e2 = Part.makeLine(v2, v3)
|
||||
e3 = Part.makeLine(v3, v4)
|
||||
e4 = Part.makeLine(v4, v1)
|
||||
edges = Part.__sortEdges__([e1, e2, e3, e4])
|
||||
rectFace = Part.Face(Part.Wire(edges))
|
||||
zTrans = obj.FinalDepth.Value - rectFace.BoundBox.ZMin
|
||||
rectFace.translate(FreeCAD.Vector(0.0, 0.0, zTrans))
|
||||
boxShp = rectFace.extrude(extVect)
|
||||
if p2.sub(p1).Length > 0:
|
||||
# Make second cylinder
|
||||
ce2 = Part.Wire(Part.makeCircle(rad, p2).Edges)
|
||||
C2 = Part.Face(ce2)
|
||||
zTrans = obj.FinalDepth.Value - C2.BoundBox.ZMin
|
||||
C2.translate(FreeCAD.Vector(0.0, 0.0, zTrans))
|
||||
endShp = C2.extrude(extVect)
|
||||
|
||||
part1 = startShp.fuse(boxShp)
|
||||
pathTravel = part1.fuse(endShp)
|
||||
# Make extruded rectangle to connect cylinders
|
||||
perp = getPerp(p1, p2, rad)
|
||||
v1 = p1.add(perp)
|
||||
v2 = p1.sub(perp)
|
||||
v3 = p2.sub(perp)
|
||||
v4 = p2.add(perp)
|
||||
e1 = Part.makeLine(v1, v2)
|
||||
e2 = Part.makeLine(v2, v3)
|
||||
e3 = Part.makeLine(v3, v4)
|
||||
e4 = Part.makeLine(v4, v1)
|
||||
edges = Part.__sortEdges__([e1, e2, e3, e4])
|
||||
rectFace = Part.Face(Part.Wire(edges))
|
||||
zTrans = obj.FinalDepth.Value - rectFace.BoundBox.ZMin
|
||||
rectFace.translate(FreeCAD.Vector(0.0, 0.0, zTrans))
|
||||
boxShp = rectFace.extrude(extVect)
|
||||
|
||||
# Fuse two cylinders and box together
|
||||
part1 = startShp.fuse(boxShp)
|
||||
pathTravel = part1.fuse(endShp)
|
||||
else:
|
||||
pathTravel = startShp
|
||||
|
||||
if self.showTempObjects:
|
||||
O = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmp_PathTravel')
|
||||
@@ -1233,35 +1285,6 @@ class ObjectSlot(PathOp.ObjectOp):
|
||||
# Eclass
|
||||
|
||||
|
||||
# Determine applicable enumerations
|
||||
def removeIndexesFromReference_1(sub, single=False):
|
||||
"""Determine which enumerations to remove for Reference1 input
|
||||
based upon the feature type(category)."""
|
||||
cat = sub[:4]
|
||||
remIdxs = [6, 5, 4]
|
||||
if cat == 'Face':
|
||||
if single:
|
||||
remIdxs = [6, 3, 2, 1, 0]
|
||||
elif cat == 'Edge':
|
||||
if single:
|
||||
remIdxs = [6, 5, 3, 2, 1, 0]
|
||||
elif cat == 'Vert':
|
||||
remIdxs = [5, 4, 3, 2, 1, 0]
|
||||
return remIdxs
|
||||
|
||||
|
||||
def removeIndexesFromReference_2(sub):
|
||||
"""Determine which enumerations to remove for Reference2 input
|
||||
based upon the feature type(category)."""
|
||||
cat = sub[:4]
|
||||
remIdxs = [4]
|
||||
# Customize Reference combobox options
|
||||
if cat == 'Vert':
|
||||
remIdxs = [3, 2, 1, 0]
|
||||
return remIdxs
|
||||
|
||||
|
||||
|
||||
def SetupProperties():
|
||||
''' SetupProperties() ... Return list of properties required for operation.'''
|
||||
return [tup[1] for tup in ObjectSlot.opPropertyDefinitions(False)]
|
||||
|
||||
@@ -37,33 +37,75 @@ __doc__ = "Slot operation page controller and command implementation."
|
||||
__contributors__ = ""
|
||||
|
||||
|
||||
DEBUG = False
|
||||
|
||||
def debugMsg(msg):
|
||||
global DEBUG
|
||||
if DEBUG:
|
||||
FreeCAD.Console.PrintMessage('PathSlotGui:: ' + msg + '\n')
|
||||
|
||||
|
||||
class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
'''Page controller class for the Slot operation.'''
|
||||
|
||||
def getForm(self):
|
||||
'''getForm() ... returns UI'''
|
||||
debugMsg('getForm()')
|
||||
return FreeCADGui.PySideUic.loadUi(":/panels/PageOpSlotEdit.ui")
|
||||
|
||||
def initPage(self, obj):
|
||||
'''initPage(obj) ... Is called after getForm() to initiate the task panel.'''
|
||||
debugMsg('initPage()')
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.CATS = [None, None]
|
||||
self.propEnums = PathSlot.ObjectSlot.opPropertyEnumerations(False)
|
||||
self.ENUMS = dict()
|
||||
self.setTitle("Slot - " + obj.Label)
|
||||
# retrieve property enumerations
|
||||
self.propEnums = PathSlot.ObjectSlot.opPropertyEnumerations(False)
|
||||
# Requirements due to Gui::QuantitySpinBox class use in UI panel
|
||||
self.geo1Extension = PathGui.QuantitySpinBox(self.form.geo1Extension, obj, 'ExtendPathStart')
|
||||
self.geo2Extension = PathGui.QuantitySpinBox(self.form.geo2Extension, obj, 'ExtendPathEnd')
|
||||
# self.updateVisibility()
|
||||
|
||||
def getForm(self):
|
||||
'''getForm() ... returns UI'''
|
||||
# FreeCAD.Console.PrintMessage('getForm()\n')
|
||||
return FreeCADGui.PySideUic.loadUi(":/panels/PageOpSlotEdit.ui")
|
||||
def setFields(self, obj):
|
||||
'''setFields(obj) ... transfers obj's property values to UI'''
|
||||
debugMsg('setFields()')
|
||||
debugMsg('... calling updateVisibility()')
|
||||
self.updateVisibility()
|
||||
|
||||
self.updateQuantitySpinBoxes()
|
||||
|
||||
self.setupToolController(obj, self.form.toolController)
|
||||
self.setupCoolant(obj, self.form.coolantController)
|
||||
|
||||
enums = self.propEnums['Reference1']
|
||||
if 'Reference1' in self.ENUMS:
|
||||
enums = self.ENUMS['Reference1']
|
||||
debugMsg(' -enums1: {}'.format(enums))
|
||||
idx = enums.index(obj.Reference1)
|
||||
self.form.geo1Reference.setCurrentIndex(idx)
|
||||
|
||||
enums = self.propEnums['Reference2']
|
||||
if 'Reference2' in self.ENUMS:
|
||||
enums = self.ENUMS['Reference2']
|
||||
debugMsg(' -enums2: {}'.format(enums))
|
||||
idx = enums.index(obj.Reference2)
|
||||
self.form.geo2Reference.setCurrentIndex(idx)
|
||||
|
||||
self.selectInComboBox(obj.LayerMode, self.form.layerMode)
|
||||
self.selectInComboBox(obj.PathOrientation, self.form.pathOrientation)
|
||||
|
||||
if obj.ReverseDirection:
|
||||
self.form.reverseDirection.setCheckState(QtCore.Qt.Checked)
|
||||
else:
|
||||
self.form.reverseDirection.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
def updateQuantitySpinBoxes(self):
|
||||
# FreeCAD.Console.PrintMessage('updateQuantitySpinBoxes()\n')
|
||||
self.geo1Extension.updateSpinBox()
|
||||
self.geo2Extension.updateSpinBox()
|
||||
|
||||
def getFields(self, obj):
|
||||
'''getFields(obj) ... transfers values from UI to obj's proprties'''
|
||||
# FreeCAD.Console.PrintMessage('getFields()\n')
|
||||
debugMsg('getFields()')
|
||||
self.updateToolController(obj, self.form.toolController)
|
||||
self.updateCoolant(obj, self.form.coolantController)
|
||||
|
||||
@@ -79,36 +121,11 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
val = self.propEnums['PathOrientation'][self.form.pathOrientation.currentIndex()]
|
||||
obj.PathOrientation = val
|
||||
|
||||
if hasattr(self.form, 'reverseDirection'):
|
||||
obj.ReverseDirection = self.form.reverseDirection.isChecked()
|
||||
|
||||
def setFields(self, obj):
|
||||
'''setFields(obj) ... transfers obj's property values to UI'''
|
||||
# FreeCAD.Console.PrintMessage('setFields()\n')
|
||||
self.updateQuantitySpinBoxes()
|
||||
|
||||
self.setupToolController(obj, self.form.toolController)
|
||||
self.setupCoolant(obj, self.form.coolantController)
|
||||
|
||||
idx = self.propEnums['Reference1'].index(obj.Reference1)
|
||||
self.form.geo1Reference.setCurrentIndex(idx)
|
||||
idx = self.propEnums['Reference2'].index(obj.Reference2)
|
||||
self.form.geo2Reference.setCurrentIndex(idx)
|
||||
|
||||
self.selectInComboBox(obj.LayerMode, self.form.layerMode)
|
||||
self.selectInComboBox(obj.PathOrientation, self.form.pathOrientation)
|
||||
|
||||
if obj.ReverseDirection:
|
||||
self.form.reverseDirection.setCheckState(QtCore.Qt.Checked)
|
||||
else:
|
||||
self.form.reverseDirection.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
# FreeCAD.Console.PrintMessage('... calling updateVisibility()\n')
|
||||
self.updateVisibility()
|
||||
obj.ReverseDirection = self.form.reverseDirection.isChecked()
|
||||
|
||||
def getSignalsForUpdate(self, obj):
|
||||
'''getSignalsForUpdate(obj) ... return list of signals for updating obj'''
|
||||
# FreeCAD.Console.PrintMessage('getSignalsForUpdate()\n')
|
||||
debugMsg('getSignalsForUpdate()')
|
||||
signals = []
|
||||
signals.append(self.form.toolController.currentIndexChanged)
|
||||
signals.append(self.form.coolantController.currentIndexChanged)
|
||||
@@ -123,7 +140,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
|
||||
def updateVisibility(self, sentObj=None):
|
||||
'''updateVisibility(sentObj=None)... Updates visibility of Tasks panel objects.'''
|
||||
# FreeCAD.Console.PrintMessage('updateVisibility()\n')
|
||||
# debugMsg('updateVisibility()')
|
||||
hideFeatures = True
|
||||
if hasattr(self.obj, 'Base'):
|
||||
if self.obj.Base:
|
||||
@@ -136,8 +153,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
subCnt = len(sublist)
|
||||
|
||||
if subCnt == 1:
|
||||
debugMsg(' -subCnt == 1')
|
||||
# Save value, then reset choices
|
||||
self.resetRef1Choices()
|
||||
n1 = sublist[0]
|
||||
s1 = getattr(base.Shape, n1)
|
||||
# Show Reference1 and cusomize options within
|
||||
@@ -152,8 +169,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
if self.CATS[1]:
|
||||
self.CATS[1] = None
|
||||
elif subCnt == 2:
|
||||
self.resetRef1Choices()
|
||||
self.resetRef2Choices()
|
||||
debugMsg(' -subCnt == 2')
|
||||
n1 = sublist[0]
|
||||
n2 = sublist[1]
|
||||
s1 = getattr(base.Shape, n1)
|
||||
@@ -171,64 +187,55 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
|
||||
else:
|
||||
self.form.pathOrientation_label.hide()
|
||||
self.form.pathOrientation.hide()
|
||||
|
||||
if hideFeatures:
|
||||
# reset values
|
||||
self.CATS = [None, None]
|
||||
self.selectInComboBox('Start to End', self.form.pathOrientation)
|
||||
# hide inputs and show message
|
||||
self.form.featureReferences.hide()
|
||||
self.form.customPoints.show()
|
||||
|
||||
"""
|
||||
'Reference1': ['Center of Mass', 'Center of BoundBox',
|
||||
'Lowest Point', 'Highest Point', 'Long Edge',
|
||||
'Short Edge', 'Vertex'],
|
||||
'Reference2': ['Center of Mass', 'Center of BoundBox',
|
||||
'Lowest Point', 'Highest Point', 'Vertex']
|
||||
"""
|
||||
|
||||
def customizeReference_1(self, sub, single=False):
|
||||
debugMsg('customizeReference_1()')
|
||||
# Customize Reference1 combobox options
|
||||
# by removing unavailable choices
|
||||
cat = sub[:4]
|
||||
if cat != self.CATS[0]:
|
||||
self.CATS[0] = cat
|
||||
cBox = self.form.geo1Reference
|
||||
cBox.blockSignals(True)
|
||||
for ri in PathSlot.removeIndexesFromReference_1(sub, single):
|
||||
cBox.removeItem(ri)
|
||||
cBox.blockSignals(False)
|
||||
slot = PathSlot.ObjectSlot
|
||||
enums = slot._makeReference1Enumerations(slot, sub, single)
|
||||
self.ENUMS['Reference1'] = enums
|
||||
debugMsg('Ref1: {}'.format(enums))
|
||||
self._updateComboBox(self.form.geo1Reference, enums)
|
||||
# self.form.geo1Reference.setCurrentIndex(0)
|
||||
# self.form.geo1Reference.setCurrentText(enums[0])
|
||||
|
||||
def customizeReference_2(self, sub):
|
||||
debugMsg('customizeReference_2()')
|
||||
# Customize Reference2 combobox options
|
||||
# by removing unavailable choices
|
||||
cat = sub[:4]
|
||||
if cat != self.CATS[1]:
|
||||
self.CATS[1] = cat
|
||||
cBox = self.form.geo2Reference
|
||||
cBox.blockSignals(True)
|
||||
for ri in PathSlot.removeIndexesFromReference_2(sub):
|
||||
cBox.removeItem(ri)
|
||||
cBox.blockSignals(False)
|
||||
cBox.setCurrentIndex(0)
|
||||
|
||||
def resetRef1Choices(self):
|
||||
# Reset Reference1 choices
|
||||
ref1 = self.form.geo1Reference
|
||||
ref1.blockSignals(True)
|
||||
ref1.clear() # Empty the combobox
|
||||
ref1.addItems(self.propEnums['Reference1'])
|
||||
ref1.blockSignals(False)
|
||||
|
||||
def resetRef2Choices(self):
|
||||
# Reset Reference2 choices
|
||||
ref2 = self.form.geo2Reference
|
||||
ref2.blockSignals(True)
|
||||
ref2.clear() # Empty the combobox
|
||||
ref2.addItems(self.propEnums['Reference2'])
|
||||
ref2.blockSignals(False)
|
||||
slot = PathSlot.ObjectSlot
|
||||
enums = slot._makeReference2Enumerations(slot, sub)
|
||||
self.ENUMS['Reference2'] = enums
|
||||
debugMsg('Ref2: {}'.format(enums))
|
||||
self._updateComboBox(self.form.geo2Reference, enums)
|
||||
# self.form.geo2Reference.setCurrentIndex(0)
|
||||
# self.form.geo2Reference.setCurrentText(enums[0])
|
||||
|
||||
def registerSignalHandlers(self, obj):
|
||||
# FreeCAD.Console.PrintMessage('registerSignalHandlers()\n')
|
||||
# debugMsg('registerSignalHandlers()')
|
||||
# self.form.pathOrientation.currentIndexChanged.connect(self.updateVisibility)
|
||||
pass
|
||||
|
||||
def _updateComboBox(self, cBox, enums):
|
||||
cBox.blockSignals(True)
|
||||
cBox.clear()
|
||||
cBox.addItems(enums)
|
||||
cBox.blockSignals(False)
|
||||
|
||||
Command = PathOpGui.SetupOperation('Slot',
|
||||
PathSlot.Create,
|
||||
|
||||
@@ -235,7 +235,6 @@ void CosmeticEdgePy::setStart(Py::Object arg)
|
||||
|
||||
pNew = DrawUtil::invertY(pNew);
|
||||
Base::Vector3d pEnd = getCosmeticEdgePtr()->permaEnd;
|
||||
pEnd = DrawUtil::invertY(pEnd);
|
||||
gp_Pnt gp1(pNew.x,pNew.y,pNew.z);
|
||||
gp_Pnt gp2(pEnd.x,pEnd.y,pEnd.z);
|
||||
TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp1, gp2);
|
||||
@@ -269,7 +268,6 @@ void CosmeticEdgePy::setEnd(Py::Object arg)
|
||||
|
||||
pNew = DrawUtil::invertY(pNew);
|
||||
Base::Vector3d pStart = getCosmeticEdgePtr()->permaStart;
|
||||
pStart = DrawUtil::invertY(pStart);
|
||||
gp_Pnt gp1(pNew.x,pNew.y,pNew.z);
|
||||
gp_Pnt gp2(pStart.x,pStart.y,pStart.z);
|
||||
TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp2, gp1);
|
||||
|
||||
@@ -117,6 +117,7 @@ DrawViewDetail::DrawViewDetail()
|
||||
//hide Properties not relevant to DVDetail
|
||||
Direction.setStatus(App::Property::ReadOnly,true); //Should be same as BaseView
|
||||
Rotation.setStatus(App::Property::ReadOnly,true); //same as BaseView
|
||||
ScaleType.setValue("Custom"); //dvd uses scale from BaseView
|
||||
}
|
||||
|
||||
DrawViewDetail::~DrawViewDetail()
|
||||
@@ -471,10 +472,8 @@ void DrawViewDetail::unsetupObject()
|
||||
if (base != nullptr) {
|
||||
base->requestPaint();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DrawViewDetail::getParameters()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -472,6 +472,8 @@ void TaskDetail::createDetail()
|
||||
m_detailName.c_str(),m_baseName.c_str());
|
||||
Gui::Command::doCommand(Command::Doc,"App.activeDocument().%s.XDirection = App.activeDocument().%s.XDirection",
|
||||
m_detailName.c_str(),m_baseName.c_str());
|
||||
Gui::Command::doCommand(Command::Doc,"App.activeDocument().%s.Scale = App.activeDocument().%s.Scale",
|
||||
m_detailName.c_str(),m_baseName.c_str());
|
||||
Gui::Command::doCommand(Command::Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",
|
||||
m_pageName.c_str(), m_detailName.c_str());
|
||||
|
||||
|
||||
@@ -45,16 +45,16 @@
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
|
||||
#include <Mod/TechDraw/App/DrawPage.h>
|
||||
#include <Mod/TechDraw/App/DrawProjGroupItem.h>
|
||||
#include <Mod/TechDraw/App/DrawProjGroup.h>
|
||||
#include <Mod/TechDraw/App/DrawUtil.h>
|
||||
#include <Mod/TechDraw/App/DrawView.h>
|
||||
#include <Mod/TechDraw/App/DrawViewPart.h>
|
||||
|
||||
#include <Mod/TechDraw/App/DrawProjGroupItem.h>
|
||||
#include <Mod/TechDraw/App/DrawProjGroup.h>
|
||||
|
||||
#include "ViewProviderPage.h"
|
||||
#include "ViewProviderProjGroup.h"
|
||||
#include "ViewProviderProjGroupItem.h"
|
||||
#include "ViewProviderPage.h"
|
||||
|
||||
#include "TaskProjGroup.h"
|
||||
#include <Mod/TechDraw/Gui/ui_TaskProjGroup.h>
|
||||
|
||||
@@ -86,6 +86,13 @@ TaskProjGroup::TaskProjGroup(TechDraw::DrawProjGroup* featView, bool mode) :
|
||||
ui->sbScaleDen->setEnabled(false);
|
||||
}
|
||||
|
||||
ui->cbAutoDistribute->setChecked(multiView->AutoDistribute.getValue());
|
||||
// disable if no AutoDistribute
|
||||
ui->sbXSpacing->setEnabled(multiView->AutoDistribute.getValue());
|
||||
ui->sbYSpacing->setEnabled(multiView->AutoDistribute.getValue());
|
||||
ui->sbXSpacing->setValue(multiView->spacingX.getValue());
|
||||
ui->sbYSpacing->setValue(multiView->spacingY.getValue());
|
||||
|
||||
// Initially toggle view checkboxes if needed
|
||||
setupViewCheckboxes(true);
|
||||
|
||||
@@ -112,6 +119,13 @@ TaskProjGroup::TaskProjGroup(TechDraw::DrawProjGroup* featView, bool mode) :
|
||||
// connect(ui->projection, SIGNAL(currentIndexChanged(int)), this, SLOT(projectionTypeChanged(int)));
|
||||
connect(ui->projection, SIGNAL(currentIndexChanged(QString)), this, SLOT(projectionTypeChanged(QString)));
|
||||
|
||||
// Spacing
|
||||
connect(ui->cbAutoDistribute, SIGNAL(clicked(bool)), this, SLOT(AutoDistributeClicked(bool)));
|
||||
connect(ui->sbXSpacing, SIGNAL(valueChanged(double)), this, SLOT(spacingChanged(void)));
|
||||
connect(ui->sbYSpacing, SIGNAL(valueChanged(double)), this, SLOT(spacingChanged(void)));
|
||||
ui->sbXSpacing->setUnit(Base::Unit::Length);
|
||||
ui->sbYSpacing->setUnit(Base::Unit::Length);
|
||||
|
||||
m_page = multiView->findParentPage();
|
||||
Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_page->getDocument());
|
||||
Gui::ViewProvider* vp = activeGui->getViewProvider(m_page);
|
||||
@@ -135,6 +149,9 @@ void TaskProjGroup::saveGroupState()
|
||||
m_saveProjType = multiView->ProjectionType.getValueAsString();
|
||||
m_saveScaleType = multiView->ScaleType.getValueAsString();
|
||||
m_saveScale = multiView->Scale.getValue();
|
||||
m_saveAutoDistribute = multiView->AutoDistribute.getValue();
|
||||
m_saveSpacingX = multiView->spacingX.getValue();
|
||||
m_saveSpacingY = multiView->spacingY.getValue();
|
||||
DrawProjGroupItem* anchor = multiView->getAnchor();
|
||||
m_saveDirection = anchor->Direction.getValue();
|
||||
}
|
||||
@@ -154,6 +171,9 @@ void TaskProjGroup::restoreGroupState()
|
||||
multiView->ProjectionType.setValue(m_saveProjType.c_str());
|
||||
multiView->ScaleType.setValue(m_saveScaleType.c_str());
|
||||
multiView->Scale.setValue(m_saveScale);
|
||||
multiView->AutoDistribute.setValue(m_saveAutoDistribute);
|
||||
multiView->spacingX.setValue(m_saveSpacingX);
|
||||
multiView->spacingY.setValue(m_saveSpacingY);
|
||||
multiView->purgeProjections();
|
||||
for(auto & sv : m_saveViewNames) {
|
||||
if (sv != "Front") {
|
||||
@@ -269,6 +289,25 @@ void TaskProjGroup::scaleTypeChanged(int index)
|
||||
}
|
||||
}
|
||||
|
||||
void TaskProjGroup::AutoDistributeClicked(bool b)
|
||||
{
|
||||
if (blockUpdate) {
|
||||
return;
|
||||
}
|
||||
multiView->AutoDistribute.setValue(b);
|
||||
multiView->recomputeFeature();
|
||||
}
|
||||
|
||||
void TaskProjGroup::spacingChanged(void)
|
||||
{
|
||||
if (blockUpdate) {
|
||||
return;
|
||||
}
|
||||
multiView->spacingX.setValue(ui->sbXSpacing->value().getValue());
|
||||
multiView->spacingY.setValue(ui->sbYSpacing->value().getValue());
|
||||
multiView->recomputeFeature();
|
||||
}
|
||||
|
||||
std::pair<int, int> TaskProjGroup::nearestFraction(const double val, const long int maxDenom) const
|
||||
{
|
||||
/*
|
||||
|
||||
@@ -85,6 +85,9 @@ protected Q_SLOTS:
|
||||
/* void projectionTypeChanged(int index);*/
|
||||
void projectionTypeChanged(QString qText);
|
||||
void scaleTypeChanged(int index);
|
||||
void AutoDistributeClicked(bool b);
|
||||
/// Updates item spacing
|
||||
void spacingChanged(void);
|
||||
void scaleManuallyChanged(int i);
|
||||
|
||||
protected:
|
||||
@@ -122,6 +125,9 @@ private:
|
||||
std::string m_saveProjType;
|
||||
std::string m_saveScaleType;
|
||||
double m_saveScale;
|
||||
bool m_saveAutoDistribute;
|
||||
double m_saveSpacingX;
|
||||
double m_saveSpacingY;
|
||||
Base::Vector3d m_saveDirection;
|
||||
std::vector<std::string> m_saveViewNames;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user