Merge branch 'master' into adaptive-work
This commit is contained in:
@@ -1189,6 +1189,8 @@ bool Document::saveAs(void)
|
||||
escapedstr = Base::Tools::escapeEncodeFilename(escapedstr);
|
||||
Command::doCommand(Command::Doc,"App.getDocument(\"%s\").saveAs(u\"%s\")"
|
||||
, DocName, escapedstr.c_str());
|
||||
// App::Document::saveAs() may modify the passed file name
|
||||
fi.setFile(QString::fromUtf8(d->_pcDocument->FileName.getValue()));
|
||||
setModified(false);
|
||||
getMainWindow()->appendRecentFile(fi.filePath());
|
||||
}
|
||||
|
||||
@@ -1329,6 +1329,11 @@ bool GeomBSplineCurve::isPeriodic() const
|
||||
return myCurve->IsPeriodic()==Standard_True;
|
||||
}
|
||||
|
||||
bool GeomBSplineCurve::isRational() const
|
||||
{
|
||||
return myCurve->IsRational()==Standard_True;
|
||||
}
|
||||
|
||||
bool GeomBSplineCurve::join(const Handle(Geom_BSplineCurve)& spline)
|
||||
{
|
||||
GeomConvert_CompCurveToBSplineCurve ccbc(this->myCurve);
|
||||
|
||||
@@ -296,6 +296,7 @@ public:
|
||||
int getMultiplicity(int index) const;
|
||||
int getDegree() const;
|
||||
bool isPeriodic() const;
|
||||
bool isRational() const;
|
||||
bool join(const Handle(Geom_BSplineCurve)&);
|
||||
void makeC1Continuous(double, double);
|
||||
std::list<Geometry*> toBiArcs(double tolerance) const;
|
||||
|
||||
@@ -4206,6 +4206,33 @@ bool TopoShape::findPlane(gp_Pln &pln, double tol) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool TopoShape::isInfinite() const
|
||||
{
|
||||
if (_Shape.IsNull())
|
||||
return false;
|
||||
|
||||
try {
|
||||
// If the shape is empty an exception may be thrown
|
||||
Bnd_Box bounds;
|
||||
BRepBndLib::Add(_Shape, bounds);
|
||||
bounds.SetGap(0.0);
|
||||
Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
|
||||
bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
|
||||
|
||||
if (Precision::IsInfinite(xMax - xMin))
|
||||
return true;
|
||||
if (Precision::IsInfinite(yMax - yMin))
|
||||
return true;
|
||||
if (Precision::IsInfinite(zMax - zMin))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Standard_Failure&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TopoShape::isCoplanar(const TopoShape &other, double tol) const {
|
||||
if(isNull() || other.isNull())
|
||||
return false;
|
||||
|
||||
@@ -198,6 +198,8 @@ public:
|
||||
bool isClosed() const;
|
||||
bool isCoplanar(const TopoShape &other, double tol=-1) const;
|
||||
bool findPlane(gp_Pln &pln, double tol=-1) const;
|
||||
/// Returns true if the expansion of the shape is infinite, false otherwise
|
||||
bool isInfinite() const;
|
||||
//@}
|
||||
|
||||
/** @name Boolean operation*/
|
||||
|
||||
@@ -552,6 +552,11 @@ If the shape is an edge it returns True if its vertices are the same.
|
||||
<UserDocu>isCoplanar(shape,tol=None) -- Checks if this shape is coplanar with the given shape.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="isInfinite" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>isInfinite() -- Checks if this shape has an infinite expansion.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="findPlane" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>findPlane(tol=None) -- return a plane if the shape is planar</UserDocu>
|
||||
|
||||
@@ -1896,6 +1896,17 @@ PyObject* TopoShapePy::isCoplanar(PyObject *args)
|
||||
}PY_CATCH_OCC
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::isInfinite(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return nullptr;
|
||||
|
||||
PY_TRY {
|
||||
return Py::new_reference_to(Py::Boolean(getTopoShapePtr()->isInfinite()));
|
||||
}
|
||||
PY_CATCH_OCC
|
||||
}
|
||||
|
||||
PyObject* TopoShapePy::findPlane(PyObject *args)
|
||||
{
|
||||
double tol = -1;
|
||||
|
||||
@@ -547,32 +547,33 @@ Hole::Hole()
|
||||
|
||||
readCutDefinitions();
|
||||
|
||||
ADD_PROPERTY_TYPE(Threaded, ((long)0), "Hole", App::Prop_None, "Threaded");
|
||||
ADD_PROPERTY_TYPE(Threaded, (false), "Hole", App::Prop_None, "Threaded");
|
||||
|
||||
ADD_PROPERTY_TYPE(ModelActualThread, ((long)0), "Hole", App::Prop_None, "Model actual thread");
|
||||
ADD_PROPERTY_TYPE(ThreadPitch, ((long)0), "Hole", App::Prop_None, "Thread pitch");
|
||||
ADD_PROPERTY_TYPE(ThreadAngle, ((long)0), "Hole", App::Prop_None, "Thread angle");
|
||||
ADD_PROPERTY_TYPE(ThreadCutOffInner, ((long)0), "Hole", App::Prop_None, "Thread CutOff Inner");
|
||||
ADD_PROPERTY_TYPE(ThreadCutOffOuter, ((long)0), "Hole", App::Prop_None, "Thread CutOff Outer");
|
||||
ADD_PROPERTY_TYPE(ModelActualThread, (false), "Hole", App::Prop_None, "Model actual thread");
|
||||
ADD_PROPERTY_TYPE(ThreadPitch, (0.0), "Hole", App::Prop_None, "Thread pitch");
|
||||
ADD_PROPERTY_TYPE(ThreadAngle, (0.0), "Hole", App::Prop_None, "Thread angle");
|
||||
ADD_PROPERTY_TYPE(ThreadCutOffInner, (0.0), "Hole", App::Prop_None, "Thread CutOff Inner");
|
||||
ADD_PROPERTY_TYPE(ThreadCutOffOuter, (0.0), "Hole", App::Prop_None, "Thread CutOff Outer");
|
||||
|
||||
ADD_PROPERTY_TYPE(ThreadType, ((long)0), "Hole", App::Prop_None, "Thread type");
|
||||
ADD_PROPERTY_TYPE(ThreadType, (0L), "Hole", App::Prop_None, "Thread type");
|
||||
ThreadType.setEnums(ThreadTypeEnums);
|
||||
|
||||
ADD_PROPERTY_TYPE(ThreadSize, ((long)0), "Hole", App::Prop_None, "Thread size");
|
||||
ADD_PROPERTY_TYPE(ThreadSize, (0L), "Hole", App::Prop_None, "Thread size");
|
||||
ThreadSize.setEnums(ThreadSize_None_Enums);
|
||||
|
||||
ADD_PROPERTY_TYPE(ThreadClass, ((long)0), "Hole", App::Prop_None, "Thread class");
|
||||
ADD_PROPERTY_TYPE(ThreadClass, (0L), "Hole", App::Prop_None, "Thread class");
|
||||
ThreadClass.setEnums(ThreadClass_None_Enums);
|
||||
|
||||
ADD_PROPERTY_TYPE(ThreadFit, ((long)0), "Hole", App::Prop_None, "Thread fit");
|
||||
ADD_PROPERTY_TYPE(ThreadFit, (0L), "Hole", App::Prop_None, "Thread fit");
|
||||
ThreadFit.setEnums(ThreadFitEnums);
|
||||
|
||||
ADD_PROPERTY_TYPE(Diameter, (6.0), "Hole", App::Prop_None, "Diameter");
|
||||
|
||||
ADD_PROPERTY_TYPE(ThreadDirection, ((long)0), "Hole", App::Prop_None, "Thread direction");
|
||||
ADD_PROPERTY_TYPE(ThreadDirection, (0L), "Hole", App::Prop_None, "Thread direction");
|
||||
ThreadDirection.setEnums(ThreadDirectionEnums);
|
||||
ThreadDirection.setReadOnly(true);
|
||||
|
||||
ADD_PROPERTY_TYPE(HoleCutType, ((long)0), "Hole", App::Prop_None, "Head cut type");
|
||||
ADD_PROPERTY_TYPE(HoleCutType, (0L), "Hole", App::Prop_None, "Head cut type");
|
||||
HoleCutType.setEnums(HoleCutType_None_Enums);
|
||||
|
||||
ADD_PROPERTY_TYPE(HoleCutDiameter, (0.0), "Hole", App::Prop_None, "Head cut diameter");
|
||||
@@ -581,17 +582,17 @@ Hole::Hole()
|
||||
|
||||
ADD_PROPERTY_TYPE(HoleCutCountersinkAngle, (90.0), "Hole", App::Prop_None, "Head cut countersink angle");
|
||||
|
||||
ADD_PROPERTY_TYPE(DepthType, ((long)0), "Hole", App::Prop_None, "Type");
|
||||
ADD_PROPERTY_TYPE(DepthType, (0L), "Hole", App::Prop_None, "Type");
|
||||
DepthType.setEnums(DepthTypeEnums);
|
||||
|
||||
ADD_PROPERTY_TYPE(Depth, (25.0), "Hole", App::Prop_None, "Length");
|
||||
|
||||
ADD_PROPERTY_TYPE(DrillPoint, ((long)1), "Hole", App::Prop_None, "Drill point type");
|
||||
ADD_PROPERTY_TYPE(DrillPoint, (1L), "Hole", App::Prop_None, "Drill point type");
|
||||
DrillPoint.setEnums(DrillPointEnums);
|
||||
|
||||
ADD_PROPERTY_TYPE(DrillPointAngle, (118.0), "Hole", App::Prop_None, "Drill point angle");
|
||||
|
||||
ADD_PROPERTY_TYPE(Tapered, ((bool)false),"Hole", App::Prop_None, "Tapered");
|
||||
ADD_PROPERTY_TYPE(Tapered, (false),"Hole", App::Prop_None, "Tapered");
|
||||
|
||||
ADD_PROPERTY_TYPE(TaperedAngle, (90.0), "Hole", App::Prop_None, "Tapered angle");
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -119,6 +119,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="settingCoolant">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enable to include the default coolant mode in the template.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Coolant Mode</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -192,7 +205,16 @@
|
||||
<item>
|
||||
<widget class="QWidget" name="exportButtonBox" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
|
||||
@@ -35,13 +35,8 @@ __doc__ = "A collection of helper and utility functions for the Path GUI."
|
||||
def translate(context, text, disambig=None):
|
||||
return PySide.QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
LOGLEVEL = False
|
||||
|
||||
if LOGLEVEL:
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
|
||||
PathLog.trackModule(PathLog.thisModule())
|
||||
else:
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
def updateInputField(obj, prop, widget, onBeforeChange=None):
|
||||
@@ -53,7 +48,7 @@ def updateInputField(obj, prop, widget, onBeforeChange=None):
|
||||
If onBeforeChange is specified it is called before a new value is assigned to the property.
|
||||
Returns True if a new value was assigned, False otherwise (new value is the same as the current).
|
||||
'''
|
||||
value = FreeCAD.Units.Quantity(widget.text()).Value
|
||||
value = widget.property('rawValue')
|
||||
attr = PathUtil.getProperty(obj, prop)
|
||||
attrValue = attr.Value if hasattr(attr, 'Value') else attr
|
||||
|
||||
@@ -72,10 +67,10 @@ def updateInputField(obj, prop, widget, onBeforeChange=None):
|
||||
isDiff = True
|
||||
break
|
||||
if noExpr:
|
||||
widget.setReadOnly(False)
|
||||
widget.setProperty('readonly', False)
|
||||
widget.setStyleSheet("color: black")
|
||||
else:
|
||||
widget.setReadOnly(True)
|
||||
widget.setProperty('readonly', True)
|
||||
widget.setStyleSheet("color: gray")
|
||||
widget.update()
|
||||
|
||||
@@ -100,19 +95,26 @@ class QuantitySpinBox:
|
||||
'''
|
||||
|
||||
def __init__(self, widget, obj, prop, onBeforeChange=None):
|
||||
self.obj = obj
|
||||
PathLog.track(widget)
|
||||
self.widget = widget
|
||||
self.prop = prop
|
||||
self.onBeforeChange = onBeforeChange
|
||||
self.attachTo(obj, prop)
|
||||
|
||||
attr = PathUtil.getProperty(self.obj, self.prop)
|
||||
if attr is not None:
|
||||
if hasattr(attr, 'Value'):
|
||||
widget.setProperty('unit', attr.getUserPreferred()[2])
|
||||
widget.setProperty('binding', "%s.%s" % (obj.Name, prop))
|
||||
self.valid = True
|
||||
def attachTo(self, obj, prop = None):
|
||||
'''attachTo(obj, prop=None) ... use an existing editor for the given object and property'''
|
||||
self.obj = obj
|
||||
self.prop = prop
|
||||
if obj and prop:
|
||||
attr = PathUtil.getProperty(obj, prop)
|
||||
if attr is not None:
|
||||
if hasattr(attr, 'Value'):
|
||||
self.widget.setProperty('unit', attr.getUserPreferred()[2])
|
||||
self.widget.setProperty('binding', "%s.%s" % (obj.Name, prop))
|
||||
self.valid = True
|
||||
else:
|
||||
PathLog.warning(translate('PathGui', "Cannot find property %s of %s") % (prop, obj.Label))
|
||||
self.valid = False
|
||||
else:
|
||||
PathLog.warning(translate('PathGui', "Cannot find property %s of %s") % (prop, obj.Label))
|
||||
self.valid = False
|
||||
|
||||
def expression(self):
|
||||
@@ -122,6 +124,7 @@ class QuantitySpinBox:
|
||||
return ''
|
||||
|
||||
def setMinimum(self, quantity):
|
||||
'''setMinimum(quantity) ... set the minimum'''
|
||||
if self.valid:
|
||||
value = quantity.Value if hasattr(quantity, 'Value') else quantity
|
||||
self.widget.setProperty('setMinimum', value)
|
||||
|
||||
@@ -33,12 +33,15 @@ import os
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule(PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
class CommandJobCreate:
|
||||
'''
|
||||
@@ -87,7 +90,6 @@ class CommandJobTemplateExport:
|
||||
on Job creation and be available for selection.
|
||||
'''
|
||||
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -111,7 +113,6 @@ class CommandJobTemplateExport:
|
||||
return job
|
||||
return None
|
||||
|
||||
|
||||
def IsActive(self):
|
||||
return self.GetJob() is not None
|
||||
|
||||
@@ -163,7 +164,12 @@ class CommandJobTemplateExport:
|
||||
# setup sheet
|
||||
setupSheetAttrs = None
|
||||
if dialog:
|
||||
setupSheetAttrs = job.Proxy.setupSheet.templateAttributes(dialog.includeSettingToolRapid(), dialog.includeSettingOperationHeights(), dialog.includeSettingOperationDepths(), dialog.includeSettingOpsSettings())
|
||||
setupSheetAttrs = job.Proxy.setupSheet.templateAttributes(
|
||||
dialog.includeSettingToolRapid(),
|
||||
dialog.includeSettingCoolant(),
|
||||
dialog.includeSettingOperationHeights(),
|
||||
dialog.includeSettingOperationDepths(),
|
||||
dialog.includeSettingOpsSettings())
|
||||
else:
|
||||
setupSheetAttrs = job.Proxy.setupSheet.templateAttributes(True, True, True)
|
||||
if setupSheetAttrs:
|
||||
@@ -174,10 +180,10 @@ class CommandJobTemplateExport:
|
||||
with open(PathUtil.toUnicode(path), 'w') as fp:
|
||||
json.dump(encoded, fp, sort_keys=True, indent=2)
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Job', CommandJobCreate())
|
||||
FreeCADGui.addCommand('Path_ExportTemplate', CommandJobTemplateExport())
|
||||
|
||||
FreeCAD.Console.PrintLog("Loading PathJobCmd... done\n")
|
||||
|
||||
|
||||
@@ -32,12 +32,15 @@ import os
|
||||
from PySide import QtCore, QtGui
|
||||
from collections import Counter
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule(PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
class _ItemDelegate(QtGui.QStyledItemDelegate):
|
||||
|
||||
@@ -148,7 +151,6 @@ class JobCreate:
|
||||
self.model = QtGui.QStandardItemModel(self.dialog)
|
||||
self.model.setHorizontalHeaderLabels(['Model', 'Count'])
|
||||
|
||||
|
||||
if self.itemsSolid.hasChildren():
|
||||
self.model.appendRow(self.itemsSolid)
|
||||
if expandSolids or not (expand2Ds or expandJobs):
|
||||
@@ -244,7 +246,7 @@ class JobCreate:
|
||||
models = []
|
||||
|
||||
for i in range(self.itemsSolid.rowCount()):
|
||||
for j in range(self.itemsSolid.child(i, 1).data(QtCore.Qt.EditRole)): # pylint: disable=unused-variable
|
||||
for j in range(self.itemsSolid.child(i, 1).data(QtCore.Qt.EditRole)): # pylint: disable=unused-variable
|
||||
models.append(self.itemsSolid.child(i).data(self.DataObject))
|
||||
|
||||
for i in range(self.items2D.rowCount()):
|
||||
@@ -320,12 +322,14 @@ class JobTemplateExport:
|
||||
rapidChanged = not job.SetupSheet.Proxy.hasDefaultToolRapids()
|
||||
depthsChanged = not job.SetupSheet.Proxy.hasDefaultOperationDepths()
|
||||
heightsChanged = not job.SetupSheet.Proxy.hasDefaultOperationHeights()
|
||||
coolantChanged = not job.SetupSheet.Proxy.hasDefaultCoolantMode()
|
||||
opsWithSettings = job.SetupSheet.Proxy.operationsWithSettings()
|
||||
settingsChanged = rapidChanged or depthsChanged or heightsChanged or 0 != len(opsWithSettings)
|
||||
settingsChanged = rapidChanged or depthsChanged or heightsChanged or coolantChanged or 0 != len(opsWithSettings)
|
||||
self.dialog.settingsGroup.setChecked(settingsChanged)
|
||||
self.dialog.settingToolRapid.setChecked(rapidChanged)
|
||||
self.dialog.settingOperationDepths.setChecked(depthsChanged)
|
||||
self.dialog.settingOperationHeights.setChecked(heightsChanged)
|
||||
self.dialog.settingCoolant.setChecked(coolantChanged)
|
||||
|
||||
self.dialog.settingsOpsList.clear()
|
||||
for op in opsWithSettings:
|
||||
@@ -358,20 +362,28 @@ class JobTemplateExport:
|
||||
|
||||
def includeStock(self):
|
||||
return self.dialog.stockGroup.isChecked()
|
||||
|
||||
def includeStockExtent(self):
|
||||
return self.dialog.stockExtent.isChecked()
|
||||
|
||||
def includeStockPlacement(self):
|
||||
return self.dialog.stockPlacement.isChecked()
|
||||
|
||||
def includeSettings(self):
|
||||
return self.dialog.settingsGroup.isChecked()
|
||||
|
||||
def includeSettingToolRapid(self):
|
||||
return self.dialog.settingToolRapid.isChecked()
|
||||
|
||||
def includeSettingOperationHeights(self):
|
||||
return self.dialog.settingOperationHeights.isChecked()
|
||||
|
||||
def includeSettingOperationDepths(self):
|
||||
return self.dialog.settingOperationDepths.isChecked()
|
||||
|
||||
def includeSettingCoolant(self):
|
||||
return self.dialog.settingCoolant.isChecked()
|
||||
|
||||
def includeSettingOpsSettings(self):
|
||||
ops = []
|
||||
for i in range(self.dialog.settingsOpsList.count()):
|
||||
@@ -382,4 +394,3 @@ class JobTemplateExport:
|
||||
|
||||
def exec_(self):
|
||||
return self.dialog.exec_()
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
|
||||
return params
|
||||
|
||||
def areaOpAreaParamsExpandProfile(self, obj, isHole):
|
||||
'''areaOpPathParamsExpandProfile(obj, isHole) ... return dictionary with area parameters for expaned profile'''
|
||||
'''areaOpPathParamsExpandProfile(obj, isHole) ... return dictionary with area parameters for expanded profile'''
|
||||
params = {}
|
||||
|
||||
params['Fill'] = 1
|
||||
|
||||
@@ -35,11 +35,13 @@ __doc__ = "A container for all default values and job specific configuration val
|
||||
_RegisteredOps = {}
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule(PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
def translate(context, text, disambig=None):
|
||||
return PySide.QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
class Template:
|
||||
# pylint: disable=no-init
|
||||
|
||||
@@ -59,7 +61,7 @@ class Template:
|
||||
|
||||
def _traverseTemplateAttributes(attrs, codec):
|
||||
coded = {}
|
||||
for key,value in PathUtil.keyValueIter(attrs):
|
||||
for key, value in PathUtil.keyValueIter(attrs):
|
||||
if type(value) == dict:
|
||||
PathLog.debug("%s is a dict" % key)
|
||||
coded[key] = _traverseTemplateAttributes(value, codec)
|
||||
@@ -74,6 +76,7 @@ def _traverseTemplateAttributes(attrs, codec):
|
||||
coded[key] = value
|
||||
return coded
|
||||
|
||||
|
||||
class SetupSheet:
|
||||
'''Property container object used by a Job to hold global reference values. '''
|
||||
|
||||
@@ -92,20 +95,20 @@ class SetupSheet:
|
||||
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
obj.addProperty('App::PropertySpeed', 'VertRapid', 'ToolController', translate('PathSetupSheet', 'Default speed for horizontal rapid moves.'))
|
||||
obj.addProperty('App::PropertySpeed', 'VertRapid', 'ToolController', translate('PathSetupSheet', 'Default speed for horizontal rapid moves.'))
|
||||
obj.addProperty('App::PropertySpeed', 'HorizRapid', 'ToolController', translate('PathSetupSheet', 'Default speed for vertical rapid moves.'))
|
||||
|
||||
obj.addProperty('App::PropertyStringList', 'CoolantModes', 'CoolantMode', translate('PathSetupSheet', 'Coolant Modes'))
|
||||
obj.addProperty('App::PropertyEnumeration', 'CoolantMode', 'CoolantMode', translate('PathSetupSheet', 'Default coolant mode.'))
|
||||
|
||||
obj.addProperty('App::PropertyLength', 'SafeHeightOffset', 'OperationHeights', translate('PathSetupSheet', 'The usage of this field depends on SafeHeightExpression - by default its value is added to StartDepth and used for SafeHeight of an operation.'))
|
||||
obj.addProperty('App::PropertyString', 'SafeHeightExpression', 'OperationHeights', translate('PathSetupSheet', 'Expression set for the SafeHeight of new operations.'))
|
||||
obj.addProperty('App::PropertyLength', 'ClearanceHeightOffset', 'OperationHeights', translate('PathSetupSheet', 'The usage of this field depends on ClearanceHeightExpression - by default is value is added to StartDepth and used for ClearanceHeight of an operation.'))
|
||||
obj.addProperty('App::PropertyLength', 'SafeHeightOffset', 'OperationHeights', translate('PathSetupSheet', 'The usage of this field depends on SafeHeightExpression - by default its value is added to StartDepth and used for SafeHeight of an operation.'))
|
||||
obj.addProperty('App::PropertyString', 'SafeHeightExpression', 'OperationHeights', translate('PathSetupSheet', 'Expression set for the SafeHeight of new operations.'))
|
||||
obj.addProperty('App::PropertyLength', 'ClearanceHeightOffset', 'OperationHeights', translate('PathSetupSheet', 'The usage of this field depends on ClearanceHeightExpression - by default is value is added to StartDepth and used for ClearanceHeight of an operation.'))
|
||||
obj.addProperty('App::PropertyString', 'ClearanceHeightExpression', 'OperationHeights', translate('PathSetupSheet', 'Expression set for the ClearanceHeight of new operations.'))
|
||||
|
||||
obj.addProperty('App::PropertyString', 'StartDepthExpression', 'OperationDepths', translate('PathSetupSheet', 'Expression used for StartDepth of new operations.'))
|
||||
obj.addProperty('App::PropertyString', 'FinalDepthExpression', 'OperationDepths', translate('PathSetupSheet', 'Expression used for FinalDepth of new operations.'))
|
||||
obj.addProperty('App::PropertyString', 'StepDownExpression', 'OperationDepths', translate('PathSetupSheet', 'Expression used for StepDown of new operations.'))
|
||||
obj.addProperty('App::PropertyString', 'StepDownExpression', 'OperationDepths', translate('PathSetupSheet', 'Expression used for StepDown of new operations.'))
|
||||
|
||||
obj.SafeHeightOffset = self.decodeAttributeString(self.DefaultSafeHeightOffset)
|
||||
obj.ClearanceHeightOffset = self.decodeAttributeString(self.DefaultClearanceHeightOffset)
|
||||
@@ -154,31 +157,38 @@ class SetupSheet:
|
||||
return False
|
||||
return True
|
||||
|
||||
def hasDefaultCoolantMode(self):
|
||||
return self.obj.CoolantMode == "None"
|
||||
|
||||
def setFromTemplate(self, attrs):
|
||||
'''setFromTemplate(attrs) ... sets the default values from the given dictionary.'''
|
||||
for name in Template.All:
|
||||
if attrs.get(name) is not None:
|
||||
setattr(self.obj, name, attrs[name])
|
||||
|
||||
for opName,op in PathUtil.keyValueIter(_RegisteredOps):
|
||||
for opName, op in PathUtil.keyValueIter(_RegisteredOps):
|
||||
opSetting = attrs.get(opName)
|
||||
if opSetting is not None:
|
||||
prototype = op.prototype(opName)
|
||||
for propName in op.properties():
|
||||
value = opSetting.get(propName)
|
||||
if not value is None:
|
||||
if value is not None:
|
||||
prop = prototype.getProperty(propName)
|
||||
propertyName = OpPropertyName(opName, propName)
|
||||
propertyGroup = OpPropertyGroup(opName)
|
||||
prop.setupProperty(self.obj, propertyName, propertyGroup, prop.valueFromString(value))
|
||||
|
||||
|
||||
def templateAttributes(self, includeRapids=True, includeCoolantMode=True, includeHeights=True, includeDepths=True, includeOps=None):
|
||||
def templateAttributes(self,
|
||||
includeRapids=True,
|
||||
includeCoolantMode=True,
|
||||
includeHeights=True,
|
||||
includeDepths=True,
|
||||
includeOps=None):
|
||||
'''templateAttributes(includeRapids, includeHeights, includeDepths) ... answers a dictionary with the default values.'''
|
||||
attrs = {}
|
||||
|
||||
if includeRapids:
|
||||
attrs[Template.VertRapid] = self.obj.VertRapid.UserString
|
||||
attrs[Template.VertRapid] = self.obj.VertRapid.UserString
|
||||
attrs[Template.HorizRapid] = self.obj.HorizRapid.UserString
|
||||
|
||||
if includeCoolantMode:
|
||||
@@ -232,6 +242,7 @@ class SetupSheet:
|
||||
def encodeAttributeString(self, attr):
|
||||
'''encodeAttributeString(attr) ... return the encoded string of a template attribute.'''
|
||||
return PathUtil.toUnicode(attr.replace(self.expressionReference(), self.TemplateReference))
|
||||
|
||||
def decodeAttributeString(self, attr):
|
||||
'''decodeAttributeString(attr) ... return the decoded string of a template attribute.'''
|
||||
return PathUtil.toUnicode(attr.replace(self.TemplateReference, self.expressionReference()))
|
||||
@@ -247,7 +258,7 @@ class SetupSheet:
|
||||
def operationsWithSettings(self):
|
||||
'''operationsWithSettings() ... returns a list of operations which currently have some settings defined.'''
|
||||
ops = []
|
||||
for name,value in PathUtil.keyValueIter(_RegisteredOps):
|
||||
for name, value in PathUtil.keyValueIter(_RegisteredOps):
|
||||
for prop in value.registeredPropertyNames(name):
|
||||
if hasattr(self.obj, prop):
|
||||
ops.append(name)
|
||||
@@ -262,9 +273,9 @@ class SetupSheet:
|
||||
propName = OpPropertyName(opName, prop)
|
||||
if hasattr(self.obj, propName):
|
||||
setattr(obj, prop, getattr(self.obj, propName))
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
PathLog.info("SetupSheet has no support for {}".format(opName))
|
||||
#traceback.print_exc()
|
||||
# traceback.print_exc()
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
|
||||
@@ -272,16 +283,17 @@ class SetupSheet:
|
||||
obj.addProperty('App::PropertyStringList', 'CoolantModes', 'CoolantMode', translate('PathSetupSheet', 'Coolant Modes'))
|
||||
obj.CoolantModes = self.DefaultCoolantModes
|
||||
|
||||
|
||||
if not hasattr(obj, 'CoolantMode'):
|
||||
obj.addProperty('App::PropertyEnumeration', 'CoolantMode', 'CoolantMode', translate('PathSetupSheet', 'Default coolant mode.'))
|
||||
obj.CoolantMode = self.DefaultCoolantModes
|
||||
|
||||
def Create(name = 'SetupSheet'):
|
||||
|
||||
def Create(name='SetupSheet'):
|
||||
obj = FreeCAD.ActiveDocument.addObject('App::FeaturePython', name)
|
||||
obj.Proxy = SetupSheet(obj)
|
||||
return obj
|
||||
|
||||
|
||||
class _RegisteredOp(object):
|
||||
|
||||
def __init__(self, factory, properties):
|
||||
@@ -296,14 +308,19 @@ class _RegisteredOp(object):
|
||||
self.factory("OpPrototype.%s" % name, ptt)
|
||||
return ptt
|
||||
|
||||
|
||||
def RegisterOperation(name, objFactory, setupProperties):
|
||||
global _RegisteredOps # pylint: disable=global-statement
|
||||
global _RegisteredOps
|
||||
_RegisteredOps[name] = _RegisteredOp(objFactory, setupProperties)
|
||||
|
||||
|
||||
def OpNamePrefix(name):
|
||||
return name.replace('Path', '').replace(' ', '').replace('_', '')
|
||||
|
||||
|
||||
def OpPropertyName(opName, propName):
|
||||
return "{}{}".format(OpNamePrefix(opName), propName)
|
||||
|
||||
|
||||
def OpPropertyGroup(opName):
|
||||
return "Op {}".format(opName)
|
||||
|
||||
@@ -200,7 +200,9 @@ class ToolBit(object):
|
||||
return [prop for prop in obj.PropertiesList if obj.getGroupOfProperty(prop) == PropertyGroupAttribute]
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
obj.setEditorMode('BitShape', 1)
|
||||
# when files are shared it is essential to be able to change/set the shape file,
|
||||
# otherwise the file is hard to use
|
||||
# obj.setEditorMode('BitShape', 1)
|
||||
obj.setEditorMode('BitBody', 2)
|
||||
obj.setEditorMode('File', 1)
|
||||
obj.setEditorMode('Shape', 2)
|
||||
@@ -252,7 +254,7 @@ class ToolBit(object):
|
||||
p = findShape(p)
|
||||
if not path and p != obj.BitShape:
|
||||
obj.BitShape = p
|
||||
doc = FreeCAD.open(p)
|
||||
doc = FreeCAD.openDocument(p, True)
|
||||
obj.ShapeName = doc.Name
|
||||
docOpened = True
|
||||
return (doc, docOpened)
|
||||
@@ -286,21 +288,22 @@ class ToolBit(object):
|
||||
self._removeBitBody(obj)
|
||||
|
||||
def _setupBitShape(self, obj, path=None):
|
||||
PathLog.track(obj.Label)
|
||||
|
||||
activeDoc = FreeCAD.ActiveDocument
|
||||
(doc, docOpened) = self._loadBitBody(obj, path)
|
||||
|
||||
obj.Label = doc.RootObjects[0].Label
|
||||
self._deleteBitSetup(obj)
|
||||
obj.BitBody = obj.Document.copyObject(doc.RootObjects[0], True)
|
||||
bitBody = obj.Document.copyObject(doc.RootObjects[0], True)
|
||||
if docOpened:
|
||||
FreeCAD.setActiveDocument(activeDoc.Name)
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
|
||||
if obj.BitBody.ViewObject:
|
||||
obj.BitBody.ViewObject.Visibility = False
|
||||
self._copyBitShape(obj)
|
||||
if bitBody.ViewObject:
|
||||
bitBody.ViewObject.Visibility = False
|
||||
|
||||
for sketch in [o for o in obj.BitBody.Group if o.TypeId == 'Sketcher::SketchObject']:
|
||||
for sketch in [o for o in bitBody.Group if o.TypeId == 'Sketcher::SketchObject']:
|
||||
for constraint in [c for c in sketch.Constraints if c.Name != '']:
|
||||
typ = ParameterTypeConstraint.get(constraint.Type)
|
||||
PathLog.track(constraint, typ)
|
||||
@@ -316,6 +319,9 @@ class ToolBit(object):
|
||||
if constraint.Type == 'Angle':
|
||||
value = value * 180 / math.pi
|
||||
PathUtil.setProperty(obj, prop, value)
|
||||
# has to happen last because it could trigger op.execute evaluations
|
||||
obj.BitBody = bitBody
|
||||
self._copyBitShape(obj)
|
||||
|
||||
def getBitThumbnail(self, obj):
|
||||
if obj.BitShape:
|
||||
|
||||
@@ -62,24 +62,60 @@ class ToolBitEditor(object):
|
||||
if self.loadbitbody:
|
||||
self.tool.Proxy.loadBitBody(self.tool)
|
||||
|
||||
# remove example widgets
|
||||
layout = self.form.bitParams.layout()
|
||||
for i in range(layout.rowCount() - 1, -1, -1):
|
||||
layout.removeRow(i)
|
||||
# used to track property widgets and editors
|
||||
self.widgets = []
|
||||
|
||||
self.setupTool(self.tool)
|
||||
self.setupAttributes(self.tool)
|
||||
|
||||
def setupTool(self, tool):
|
||||
PathLog.track()
|
||||
# Can't delete and add fields to the form because of dangling references in case of
|
||||
# a focus change. see https://forum.freecadweb.org/viewtopic.php?f=10&t=52246#p458583
|
||||
# Instead we keep widgets once created and use them for new properties, and hide all
|
||||
# which aren't being needed anymore.
|
||||
|
||||
def labelText(name):
|
||||
return re.sub('([A-Z][a-z]+)', r' \1', re.sub('([A-Z]+)', r' \1', name))
|
||||
|
||||
layout = self.form.bitParams.layout()
|
||||
for i in range(layout.rowCount() - 1, -1, -1):
|
||||
layout.removeRow(i)
|
||||
editor = {}
|
||||
ui = FreeCADGui.UiLoader()
|
||||
nr = 0
|
||||
|
||||
# for all properties either assign them to existing labels and editors
|
||||
# or create additional ones for them if not enough have already been
|
||||
# created.
|
||||
for name in tool.PropertiesList:
|
||||
if tool.getGroupOfProperty(name) == PathToolBit.PropertyGroupBit:
|
||||
qsb = ui.createWidget('Gui::QuantitySpinBox')
|
||||
editor[name] = PathGui.QuantitySpinBox(qsb, tool, name)
|
||||
label = QtGui.QLabel(re.sub('([A-Z][a-z]+)', r' \1',
|
||||
re.sub('([A-Z]+)', r' \1', name)))
|
||||
layout.addRow(label, qsb)
|
||||
self.bitEditor = editor
|
||||
if nr < len(self.widgets):
|
||||
PathLog.debug("re-use row: {} [{}]".format(nr, name))
|
||||
label, qsb, editor = self.widgets[nr]
|
||||
label.setText(labelText(name))
|
||||
editor.attachTo(tool, name)
|
||||
label.show()
|
||||
qsb.show()
|
||||
else:
|
||||
qsb = ui.createWidget('Gui::QuantitySpinBox')
|
||||
editor = PathGui.QuantitySpinBox(qsb, tool, name)
|
||||
label = QtGui.QLabel(labelText(name))
|
||||
self.widgets.append((label, qsb, editor))
|
||||
PathLog.debug("create row: {} [{}]".format(nr, name))
|
||||
if nr >= layout.rowCount():
|
||||
layout.addRow(label, qsb)
|
||||
nr = nr + 1
|
||||
|
||||
# hide all rows which aren't being used
|
||||
for i in range(nr, len(self.widgets)):
|
||||
label, qsb, editor = self.widgets[i]
|
||||
label.hide()
|
||||
qsb.hide()
|
||||
editor.attachTo(None)
|
||||
PathLog.debug(" hide row: {}".format(i))
|
||||
|
||||
img = tool.Proxy.getBitThumbnail(tool)
|
||||
if img:
|
||||
self.form.image.setPixmap(QtGui.QPixmap(QtGui.QImage.fromData(img)))
|
||||
@@ -189,25 +225,28 @@ class ToolBitEditor(object):
|
||||
self.form.toolName.setText(self.tool.Label)
|
||||
self.form.shapePath.setText(self.tool.BitShape)
|
||||
|
||||
for editor in self.bitEditor:
|
||||
self.bitEditor[editor].updateSpinBox()
|
||||
for lbl, qsb, editor in self.widgets:
|
||||
editor.updateSpinBox()
|
||||
|
||||
def updateShape(self):
|
||||
PathLog.track()
|
||||
self.tool.BitShape = str(self.form.shapePath.text())
|
||||
self.setupTool(self.tool)
|
||||
self.form.toolName.setText(self.tool.Label)
|
||||
shapePath = str(self.form.shapePath.text())
|
||||
# Only need to go through this exercise if the shape actually changed.
|
||||
if self.tool.BitShape != shapePath:
|
||||
self.tool.BitShape = shapePath
|
||||
self.setupTool(self.tool)
|
||||
self.form.toolName.setText(self.tool.Label)
|
||||
|
||||
for editor in self.bitEditor:
|
||||
self.bitEditor[editor].updateSpinBox()
|
||||
for lbl, qsb, editor in self.widgets:
|
||||
editor.updateSpinBox()
|
||||
|
||||
def updateTool(self):
|
||||
PathLog.track()
|
||||
self.tool.Label = str(self.form.toolName.text())
|
||||
self.tool.BitShape = str(self.form.shapePath.text())
|
||||
|
||||
for editor in self.bitEditor:
|
||||
self.bitEditor[editor].updateProperty()
|
||||
for lbl, qsb, editor in self.widgets:
|
||||
editor.updateProperty()
|
||||
|
||||
# self.tool.Proxy._updateBitShape(self.tool)
|
||||
|
||||
|
||||
@@ -152,7 +152,9 @@ G0 Z0.500000
|
||||
table.addTools(t2)
|
||||
|
||||
self.assertEqual(len(table.Tools), 2)
|
||||
self.assertEqual(str(table.Tools), '{1: Tool 12.7mm Drill Bit, 2: Tool my other tool}' )
|
||||
# gcc7 build needs some special treatment (makes 1L out of a 1) ...
|
||||
if str(table.Tools) != '{1L: Tool 12.7mm Drill Bit, 2L: Tool my other tool}':
|
||||
self.assertEqual(str(table.Tools), '{1: Tool 12.7mm Drill Bit, 2: Tool my other tool}')
|
||||
|
||||
def test50(self):
|
||||
"""Test Path.Length calculation"""
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "SketchObject.h"
|
||||
#include "SketchGeometryExtension.h"
|
||||
#include "ExternalGeometryExtension.h"
|
||||
#include "SolverGeometryExtension.h"
|
||||
#include "GeometryFacade.h"
|
||||
#include "ExternalGeometryFacade.h"
|
||||
#include "Constraint.h"
|
||||
@@ -80,6 +81,7 @@ PyMOD_INIT_FUNC(Sketcher)
|
||||
|
||||
Sketcher::SketchGeometryExtension ::init();
|
||||
Sketcher::ExternalGeometryExtension ::init();
|
||||
Sketcher::SolverGeometryExtension ::init();
|
||||
Sketcher::GeometryFacade ::init();
|
||||
Sketcher::ExternalGeometryFacade ::init();
|
||||
Sketcher::SketchObjectSF ::init();
|
||||
|
||||
@@ -58,6 +58,8 @@ SET(Features_SRCS
|
||||
SketchGeometryExtension.h
|
||||
ExternalGeometryExtension.cpp
|
||||
ExternalGeometryExtension.h
|
||||
SolverGeometryExtension.cpp
|
||||
SolverGeometryExtension.h
|
||||
SketchObject.cpp
|
||||
SketchObject.h
|
||||
SketchAnalysis.h
|
||||
|
||||
@@ -83,7 +83,7 @@ class GeometryFacadePy;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// Note: The standard GeometryFacade stores Part::Geometry derived clases as a Part::Geometry *, while
|
||||
// Note: The standard GeometryFacade stores Part::Geometry derived classes as a Part::Geometry *, while
|
||||
// it has the ability to return a dynamic_cast-ed version to a provided type as follows:
|
||||
//
|
||||
// HLine->getGeometry<Part::GeomLineSegment>();
|
||||
|
||||
+211
-201
@@ -55,10 +55,13 @@
|
||||
#include <Mod/Part/App/LineSegmentPy.h>
|
||||
#include <Mod/Part/App/BSplineCurvePy.h>
|
||||
|
||||
#include "Sketch.h"
|
||||
#include "Constraint.h"
|
||||
|
||||
#include "GeometryFacade.h"
|
||||
#include "SolverGeometryExtension.h"
|
||||
|
||||
#include "Sketch.h"
|
||||
|
||||
|
||||
using namespace Sketcher;
|
||||
using namespace Base;
|
||||
@@ -105,6 +108,9 @@ void Sketch::clear(void)
|
||||
if (*it) delete *it;
|
||||
FixParameters.clear();
|
||||
|
||||
param2geoelement.clear();
|
||||
pDependencyGroups.clear();
|
||||
|
||||
// deleting the geometry copied into this sketch
|
||||
for (std::vector<GeoDef>::iterator it = Geoms.begin(); it != Geoms.end(); ++it)
|
||||
if (it->geo) delete it->geo;
|
||||
@@ -159,7 +165,7 @@ int Sketch::setUpSketch(const std::vector<Part::Geometry *> &GeoList,
|
||||
GCSsys.initSolution(defaultSolverRedundant);
|
||||
GCSsys.getConflicting(Conflicting);
|
||||
GCSsys.getRedundant(Redundant);
|
||||
GCSsys.getDependentParams(pconstraintplistOut);
|
||||
GCSsys.getDependentParams(pDependentParametersList);
|
||||
|
||||
calculateDependentParametersElements();
|
||||
|
||||
@@ -179,106 +185,114 @@ void Sketch::clearTemporaryConstraints(void)
|
||||
|
||||
void Sketch::calculateDependentParametersElements(void)
|
||||
{
|
||||
// initialize solve extensions to a know state
|
||||
for(auto geo : Geoms) {
|
||||
std::vector<double *> ownparams;
|
||||
GCS::Curve * pCurve = nullptr;
|
||||
|
||||
switch(geo.type) {
|
||||
case Point:
|
||||
{
|
||||
GCS::Point & point = Points[geo.startPointId];
|
||||
for(auto param : pconstraintplistOut) {
|
||||
if (param == point.x || param == point.y) {
|
||||
point.hasDependentParameters = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Line:
|
||||
{
|
||||
GCS::Line & line = Lines[geo.index];
|
||||
line.PushOwnParams(ownparams);
|
||||
pCurve = &line;
|
||||
if(!geo.geo->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId()))
|
||||
geo.geo->setExtension(std::make_unique<Sketcher::SolverGeometryExtension>());
|
||||
|
||||
auto solvext = std::static_pointer_cast<Sketcher::SolverGeometryExtension>(
|
||||
geo.geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock());
|
||||
|
||||
if(GCSsys.isEmptyDiagnoseMatrix())
|
||||
solvext->init(SolverGeometryExtension::Dependent);
|
||||
else
|
||||
solvext->init(SolverGeometryExtension::Independent);
|
||||
}
|
||||
|
||||
for(auto param : pDependentParametersList) {
|
||||
|
||||
//auto element = param2geoelement.at(param);
|
||||
auto element = param2geoelement.find(param);
|
||||
|
||||
if (element != param2geoelement.end()) {
|
||||
auto solvext = std::static_pointer_cast<Sketcher::SolverGeometryExtension>(
|
||||
Geoms[element->second.first].geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock());
|
||||
|
||||
switch(element->second.second) {
|
||||
case none:
|
||||
solvext->setEdge(SolverGeometryExtension::Dependent);
|
||||
break;
|
||||
case start:
|
||||
solvext->setStart(SolverGeometryExtension::Dependent);
|
||||
break;
|
||||
case end:
|
||||
solvext->setEnd(SolverGeometryExtension::Dependent);
|
||||
break;
|
||||
case mid:
|
||||
solvext->setMid(SolverGeometryExtension::Dependent);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Arc:
|
||||
{
|
||||
GCS::Arc & arc = Arcs[geo.index];
|
||||
arc.PushOwnParams(ownparams);
|
||||
pCurve = &arc;
|
||||
}
|
||||
break;
|
||||
case Circle:
|
||||
{
|
||||
GCS::Circle & c = Circles[geo.index];
|
||||
c.PushOwnParams(ownparams);
|
||||
pCurve = &c;
|
||||
}
|
||||
break;
|
||||
case Ellipse:
|
||||
{
|
||||
GCS::Ellipse & e = Ellipses[geo.index];
|
||||
e.PushOwnParams(ownparams);
|
||||
pCurve = &e;
|
||||
}
|
||||
break;
|
||||
case ArcOfEllipse:
|
||||
{
|
||||
GCS::ArcOfEllipse & aoe = ArcsOfEllipse[geo.index];
|
||||
aoe.PushOwnParams(ownparams);
|
||||
pCurve = &aoe;
|
||||
}
|
||||
break;
|
||||
case ArcOfHyperbola:
|
||||
{
|
||||
GCS::ArcOfHyperbola & aoh = ArcsOfHyperbola[geo.index];
|
||||
aoh.PushOwnParams(ownparams);
|
||||
pCurve = &aoh;
|
||||
}
|
||||
break;
|
||||
case ArcOfParabola:
|
||||
{
|
||||
GCS::ArcOfParabola & aop = ArcsOfParabola[geo.index];
|
||||
aop.PushOwnParams(ownparams);
|
||||
pCurve = &aop;
|
||||
}
|
||||
break;
|
||||
case BSpline:
|
||||
{
|
||||
GCS::BSpline & bsp = BSplines[geo.index];
|
||||
bsp.PushOwnParams(ownparams);
|
||||
pCurve = &bsp;
|
||||
}
|
||||
break;
|
||||
case None:
|
||||
break;
|
||||
|
||||
}
|
||||
// Points (this is single point elements, not vertices of other elements) are not derived from Curve
|
||||
if(geo.type != Point && geo.type != None) {
|
||||
for(auto param : pconstraintplistOut) {
|
||||
for(auto ownparam : ownparams) {
|
||||
if (param == ownparam) {
|
||||
pCurve->hasDependentParameters = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector < std::set < double*>> groups;
|
||||
GCSsys.getDependentParamsGroups(groups);
|
||||
|
||||
pDependencyGroups.resize(groups.size());
|
||||
|
||||
// translate parameters into elements (Geoid, PointPos)
|
||||
for(size_t i = 0; i < groups.size(); i++) {
|
||||
for(size_t j = 0; j < groups[i].size(); j++) {
|
||||
|
||||
auto element = param2geoelement.find(*std::next(groups[i].begin(), j));
|
||||
|
||||
if (element != param2geoelement.end()) {
|
||||
pDependencyGroups[i].insert(element->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Points are the only element that defines other elements, so these points (as opposed to those points
|
||||
// above which are just GeomPoints), have to be handled separately.
|
||||
for(auto & point : Points) {
|
||||
for(auto param : pconstraintplistOut) {
|
||||
if (param == point.x || param == point.y) {
|
||||
point.hasDependentParameters = true;
|
||||
break;
|
||||
|
||||
// check if groups have a common element, if yes merge the groups
|
||||
auto havecommonelement = [] ( std::set < std::pair< int, Sketcher::PointPos>>::iterator begin1,
|
||||
std::set < std::pair< int, Sketcher::PointPos>>::iterator end1,
|
||||
std::set < std::pair< int, Sketcher::PointPos>>::iterator begin2,
|
||||
std::set < std::pair< int, Sketcher::PointPos>>::iterator end2) {
|
||||
|
||||
while (begin1 != end1 && begin2 != end2) {
|
||||
if (*begin1 < *begin2)
|
||||
++begin1;
|
||||
else if (*begin2 < *begin1)
|
||||
++begin2;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if(pDependencyGroups.size() > 1) { // only if there is more than 1 group
|
||||
size_t endcount = pDependencyGroups.size()-1;
|
||||
|
||||
for(size_t i=0; i < endcount; i++) {
|
||||
if(havecommonelement(pDependencyGroups[i].begin(), pDependencyGroups[i].end(), pDependencyGroups[i+1].begin(), pDependencyGroups[i+1].end())){
|
||||
pDependencyGroups[i].insert(pDependencyGroups[i+1].begin(), pDependencyGroups[i+1].end());
|
||||
pDependencyGroups.erase(pDependencyGroups.begin()+i+1);
|
||||
endcount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set < std::pair< int, Sketcher::PointPos>> Sketch::getDependencyGroup(int geoId, PointPos pos) const
|
||||
{
|
||||
geoId = checkGeoId(geoId);
|
||||
|
||||
std::set < std::pair< int, Sketcher::PointPos>> group;
|
||||
|
||||
auto key = std::make_pair(geoId, pos);
|
||||
|
||||
for( auto & set : pDependencyGroups) {
|
||||
if (set.find(key) != set.end()) {
|
||||
group = set;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
int Sketch::resetSolver()
|
||||
{
|
||||
clearTemporaryConstraints();
|
||||
@@ -287,7 +301,7 @@ int Sketch::resetSolver()
|
||||
GCSsys.initSolution(defaultSolverRedundant);
|
||||
GCSsys.getConflicting(Conflicting);
|
||||
GCSsys.getRedundant(Redundant);
|
||||
GCSsys.getDependentParams(pconstraintplistOut);
|
||||
GCSsys.getDependentParams(pDependentParametersList);
|
||||
|
||||
calculateDependentParametersElements();
|
||||
|
||||
@@ -422,6 +436,11 @@ int Sketch::addPoint(const Part::GeomPoint &point, bool fixed)
|
||||
// store complete set
|
||||
Geoms.push_back(def);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
}
|
||||
|
||||
// return the position of the newly added geometry
|
||||
return Geoms.size()-1;
|
||||
}
|
||||
@@ -476,6 +495,13 @@ int Sketch::addLineSegment(const Part::GeomLineSegment &lineSegment, bool fixed)
|
||||
// store complete set
|
||||
Geoms.push_back(def);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace( std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
}
|
||||
|
||||
// return the position of the newly added geometry
|
||||
return Geoms.size()-1;
|
||||
}
|
||||
@@ -547,6 +573,18 @@ int Sketch::addArc(const Part::GeomArcOfCircle &circleSegment, bool fixed)
|
||||
if (!fixed)
|
||||
GCSsys.addConstraintArcRules(a);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
}
|
||||
|
||||
// return the position of the newly added geometry
|
||||
return Geoms.size()-1;
|
||||
}
|
||||
@@ -635,6 +673,20 @@ int Sketch::addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool f
|
||||
if (!fixed)
|
||||
GCSsys.addConstraintArcOfEllipseRules(a);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
}
|
||||
|
||||
// return the position of the newly added geometry
|
||||
return Geoms.size()-1;
|
||||
}
|
||||
@@ -721,6 +773,21 @@ int Sketch::addArcOfHyperbola(const Part::GeomArcOfHyperbola &hyperbolaSegment,
|
||||
if (!fixed)
|
||||
GCSsys.addConstraintArcOfHyperbolaRules(a);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
}
|
||||
|
||||
|
||||
// return the position of the newly added geometry
|
||||
return Geoms.size()-1;
|
||||
}
|
||||
@@ -797,6 +864,19 @@ int Sketch::addArcOfParabola(const Part::GeomArcOfParabola ¶bolaSegment, boo
|
||||
if (!fixed)
|
||||
GCSsys.addConstraintArcOfParabolaRules(a);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p3.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p4.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p4.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a1), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(a2), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
}
|
||||
|
||||
// return the position of the newly added geometry
|
||||
return Geoms.size()-1;
|
||||
}
|
||||
@@ -859,13 +939,23 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed)
|
||||
p.y = params[params.size()-1];
|
||||
|
||||
spoles.push_back(p);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double *> sweights;
|
||||
|
||||
for(std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it) {
|
||||
params.push_back(new double( (*it) ));
|
||||
auto r = new double( (*it) );
|
||||
params.push_back(r);
|
||||
sweights.push_back(params[params.size()-1]);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double *> sknots;
|
||||
@@ -944,6 +1034,14 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed)
|
||||
GCSsys.addConstraintP2PCoincident(*(bs.poles.end()-1),bs.end);
|
||||
}
|
||||
|
||||
if(!fixed) {
|
||||
// Note: Poles and weight parameters are emplaced above
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::start));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p2.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::end));
|
||||
}
|
||||
|
||||
// return the position of the newly added geometry
|
||||
return Geoms.size()-1;
|
||||
}
|
||||
@@ -987,6 +1085,12 @@ int Sketch::addCircle(const Part::GeomCircle &cir, bool fixed)
|
||||
// store complete set
|
||||
Geoms.push_back(def);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(p1.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(r), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
}
|
||||
|
||||
// return the position of the newly added geometry
|
||||
return Geoms.size()-1;
|
||||
}
|
||||
@@ -1045,6 +1149,14 @@ int Sketch::addEllipse(const Part::GeomEllipse &elip, bool fixed)
|
||||
// store complete set
|
||||
Geoms.push_back(def);
|
||||
|
||||
if(!fixed) {
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(c.x), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(c.y), std::forward_as_tuple(Geoms.size()-1, Sketcher::mid));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1X), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(f1Y), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
param2geoelement.emplace(std::piecewise_construct, std::forward_as_tuple(rmin), std::forward_as_tuple(Geoms.size()-1, Sketcher::none));
|
||||
}
|
||||
|
||||
// return the position of the newly added geometry
|
||||
return Geoms.size()-1;
|
||||
}
|
||||
@@ -1063,6 +1175,14 @@ std::vector<Part::Geometry *> Sketch::extractGeometry(bool withConstructionEleme
|
||||
return temp;
|
||||
}
|
||||
|
||||
void Sketch::updateExtension(int geoId, std::unique_ptr<Part::GeometryExtension> && ext)
|
||||
{
|
||||
geoId = checkGeoId(geoId);
|
||||
|
||||
Geoms[geoId].geo->setExtension(std::move(ext));
|
||||
|
||||
}
|
||||
|
||||
Py::Tuple Sketch::getPyGeometry(void) const
|
||||
{
|
||||
Py::Tuple tuple(Geoms.size());
|
||||
@@ -3692,116 +3812,6 @@ Base::Vector3d Sketch::getPoint(int geoId, PointPos pos) const
|
||||
return Base::Vector3d();
|
||||
}
|
||||
|
||||
bool Sketch::hasDependentParameters(int geoId, PointPos pos) const
|
||||
{
|
||||
try {
|
||||
geoId = checkGeoId(geoId);
|
||||
}
|
||||
catch (Base::Exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Geoms[geoId].external)
|
||||
return true;
|
||||
|
||||
switch(Geoms[geoId].type) {
|
||||
case Point:
|
||||
{
|
||||
switch(pos) { // NOTE: points are added to all the cases, see addition.
|
||||
case none: return Points[Geoms[geoId].index].hasDependentParameters;break;
|
||||
case start: return Points[Geoms[geoId].startPointId].hasDependentParameters;break;
|
||||
case end: return Points[Geoms[geoId].endPointId].hasDependentParameters;break;
|
||||
case mid: return Points[Geoms[geoId].midPointId].hasDependentParameters;break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Line:
|
||||
{
|
||||
switch(pos) {
|
||||
case none: return Lines[Geoms[geoId].index].hasDependentParameters;break;
|
||||
case start: return Points[Geoms[geoId].startPointId].hasDependentParameters;break;
|
||||
case end: return Points[Geoms[geoId].endPointId].hasDependentParameters;break;
|
||||
case mid: return false;break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Arc:
|
||||
{
|
||||
switch(pos) {
|
||||
case none: return Arcs[Geoms[geoId].index].hasDependentParameters;break;
|
||||
case start: return Points[Geoms[geoId].startPointId].hasDependentParameters;break;
|
||||
case end: return Points[Geoms[geoId].endPointId].hasDependentParameters;break;
|
||||
case mid: return Points[Geoms[geoId].midPointId].hasDependentParameters;break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Circle:
|
||||
{
|
||||
switch(pos) { // NOTE: points are added to all the cases, see addition.
|
||||
case none: return Circles[Geoms[geoId].index].hasDependentParameters;break;
|
||||
case start: return false;break;
|
||||
case end: return false;break;
|
||||
case mid: return Points[Geoms[geoId].midPointId].hasDependentParameters;break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Ellipse:
|
||||
{
|
||||
switch(pos) { // NOTE: points are added to all the cases, see addition.
|
||||
case none: return Ellipses[Geoms[geoId].index].hasDependentParameters;break;
|
||||
case start: return false;break;
|
||||
case end: return false;break;
|
||||
case mid: return Points[Geoms[geoId].midPointId].hasDependentParameters;break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ArcOfEllipse:
|
||||
{
|
||||
switch(pos) {
|
||||
case none: return ArcsOfEllipse[Geoms[geoId].index].hasDependentParameters;break;
|
||||
case start: return Points[Geoms[geoId].startPointId].hasDependentParameters;break;
|
||||
case end: return Points[Geoms[geoId].endPointId].hasDependentParameters;break;
|
||||
case mid: return Points[Geoms[geoId].midPointId].hasDependentParameters;break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ArcOfHyperbola:
|
||||
{
|
||||
switch(pos) {
|
||||
case none: return ArcsOfHyperbola[Geoms[geoId].index].hasDependentParameters;break;
|
||||
case start: return Points[Geoms[geoId].startPointId].hasDependentParameters;break;
|
||||
case end: return Points[Geoms[geoId].endPointId].hasDependentParameters;break;
|
||||
case mid: return Points[Geoms[geoId].midPointId].hasDependentParameters;break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ArcOfParabola:
|
||||
{
|
||||
switch(pos) {
|
||||
case none: return ArcsOfParabola[Geoms[geoId].index].hasDependentParameters;break;
|
||||
case start: return Points[Geoms[geoId].startPointId].hasDependentParameters;break;
|
||||
case end: return Points[Geoms[geoId].endPointId].hasDependentParameters;break;
|
||||
case mid: return Points[Geoms[geoId].midPointId].hasDependentParameters;break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BSpline:
|
||||
{
|
||||
switch(pos) {
|
||||
case none: return BSplines[Geoms[geoId].index].hasDependentParameters;break;
|
||||
case start: return Points[Geoms[geoId].startPointId].hasDependentParameters;break;
|
||||
case end: return Points[Geoms[geoId].endPointId].hasDependentParameters;break;
|
||||
case mid: return false;break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case None:
|
||||
return false; break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TopoShape Sketch::toShape(void) const
|
||||
{
|
||||
TopoShape result;
|
||||
|
||||
@@ -88,6 +88,8 @@ public:
|
||||
/// returns the actual geometry
|
||||
std::vector<Part::Geometry *> extractGeometry(bool withConstructionElements=true,
|
||||
bool withExternalElements=false) const;
|
||||
|
||||
void updateExtension(int geoId, std::unique_ptr<Part::GeometryExtension> && ext);
|
||||
/// get the geometry as python objects
|
||||
Py::Tuple getPyGeometry(void) const;
|
||||
|
||||
@@ -96,9 +98,6 @@ public:
|
||||
/// retrieves a point
|
||||
Base::Vector3d getPoint(int geoId, PointPos pos) const;
|
||||
|
||||
/// retrieves whether a geometry has dependent parameters or not
|
||||
bool hasDependentParameters(int geoId, PointPos pos) const;
|
||||
|
||||
// Inline methods
|
||||
inline bool hasConflicts(void) const { return !Conflicting.empty(); }
|
||||
inline const std::vector<int> &getConflicting(void) const { return Conflicting; }
|
||||
@@ -106,6 +105,11 @@ public:
|
||||
inline const std::vector<int> &getRedundant(void) const { return Redundant; }
|
||||
|
||||
inline bool hasMalformedConstraints(void) const { return malformedConstraints; }
|
||||
public:
|
||||
std::set < std::pair< int, Sketcher::PointPos>> getDependencyGroup(int geoId, PointPos pos) const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** set the datum of a distance or angle constraint to a certain value and solve
|
||||
* This can cause the solving to fail!
|
||||
@@ -409,7 +413,12 @@ protected:
|
||||
std::vector<int> Conflicting;
|
||||
std::vector<int> Redundant;
|
||||
|
||||
std::vector<double *> pconstraintplistOut;
|
||||
std::vector<double *> pDependentParametersList;
|
||||
|
||||
std::vector < std::set < std::pair< int, Sketcher::PointPos>>> pDependencyGroups;
|
||||
|
||||
// this map is intended to convert a parameter (double *) into a GeoId/PointPos pair
|
||||
std::map<double *, std::pair<int,Sketcher::PointPos>> param2geoelement;
|
||||
|
||||
// solving parameters
|
||||
std::vector<double*> Parameters; // with memory allocation
|
||||
|
||||
@@ -79,10 +79,12 @@
|
||||
#include <Mod/Part/App/BodyBase.h>
|
||||
#include <Mod/Part/App/GeometryMigrationExtension.h>
|
||||
|
||||
#include "SketchObject.h"
|
||||
#include "Sketch.h"
|
||||
#include <Mod/Sketcher/App/Sketch.h>
|
||||
#include <Mod/Sketcher/App/SketchObjectPy.h>
|
||||
#include <Mod/Sketcher/App/SketchGeometryExtensionPy.h>
|
||||
#include <Mod/Sketcher/App/SolverGeometryExtension.h>
|
||||
|
||||
#include "SketchObject.h"
|
||||
|
||||
|
||||
#undef DEBUG
|
||||
@@ -146,7 +148,6 @@ SketchObject::SketchObject()
|
||||
|
||||
internaltransaction=false;
|
||||
managedoperation=false;
|
||||
deletinginternalgeometry=false;
|
||||
}
|
||||
|
||||
SketchObject::~SketchObject()
|
||||
@@ -957,10 +958,6 @@ int SketchObject::delGeometry(int GeoId, bool deleteinternalgeo)
|
||||
|
||||
this->deleteUnusedInternalGeometry(GeoId, true);
|
||||
|
||||
Geometry.touch();
|
||||
|
||||
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver
|
||||
solve();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1002,13 +999,12 @@ int SketchObject::delGeometry(int GeoId, bool deleteinternalgeo)
|
||||
this->Geometry.setValues(newVals);
|
||||
this->Constraints.setValues(std::move(newConstraints));
|
||||
}
|
||||
// Update geometry indices and rebuild vertexindex now via onChanged, so that ViewProvider::UpdateData is triggered.
|
||||
if(!deletinginternalgeometry) {
|
||||
Geometry.touch();
|
||||
|
||||
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver
|
||||
solve();
|
||||
}
|
||||
// Update geometry indices and rebuild vertexindex now via onChanged, so that ViewProvider::UpdateData is triggered.
|
||||
Geometry.touch();
|
||||
|
||||
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver
|
||||
solve();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4979,8 +4975,6 @@ int SketchObject::exposeInternalGeometry(int GeoId)
|
||||
|
||||
int SketchObject::deleteUnusedInternalGeometry(int GeoId, bool delgeoid)
|
||||
{
|
||||
Base::StateLocker lock(deletinginternalgeometry, true);
|
||||
|
||||
if (GeoId < 0 || GeoId > getHighestCurveIndex())
|
||||
return -1;
|
||||
|
||||
@@ -5264,16 +5258,7 @@ int SketchObject::deleteUnusedInternalGeometry(int GeoId, bool delgeoid)
|
||||
if(delgeoid)
|
||||
delgeometries.push_back(GeoId);
|
||||
|
||||
std::sort(delgeometries.begin(), delgeometries.end()); // indices over an erased element get automatically updated!!
|
||||
|
||||
if (delgeometries.size()>0) {
|
||||
for (std::vector<int>::reverse_iterator it=delgeometries.rbegin(); it!=delgeometries.rend(); ++it) {
|
||||
delGeometry(*it,false);
|
||||
}
|
||||
}
|
||||
|
||||
int ndeleted = delgeometries.size();
|
||||
delgeometries.clear();
|
||||
int ndeleted = delGeometries(delgeometries);
|
||||
|
||||
return ndeleted; //number of deleted elements
|
||||
}
|
||||
@@ -7025,55 +7010,47 @@ void SketchObject::getGeometryWithDependentParameters(std::vector<std::pair<int,
|
||||
{
|
||||
auto geos = getInternalGeometry();
|
||||
|
||||
GCS::QRAlgorithm curQRAlg = getSolvedSketch().getQRAlgorithm();
|
||||
|
||||
if(curQRAlg == GCS::EigenSparseQR) {
|
||||
getSolvedSketch().setQRAlgorithm(GCS::EigenDenseQR);
|
||||
solve(false);
|
||||
}
|
||||
|
||||
auto addelement = [this,&geometrymap](int geoId, PointPos pos){
|
||||
if(getSolvedSketch().hasDependentParameters(geoId, pos))
|
||||
geometrymap.emplace_back(geoId,pos);
|
||||
};
|
||||
|
||||
|
||||
int geoid = 0;
|
||||
|
||||
for(auto geo : geos) {
|
||||
if(geo->getTypeId() == Part::GeomPoint::getClassTypeId()) {
|
||||
addelement(geoid, Sketcher::start);
|
||||
}
|
||||
else if(geo->getTypeId() == Part::GeomLineSegment::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) {
|
||||
if(geo) {
|
||||
if(geo->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) {
|
||||
|
||||
addelement(geoid, Sketcher::start);
|
||||
addelement(geoid, Sketcher::end);
|
||||
addelement(geoid, Sketcher::none);
|
||||
}
|
||||
else if(geo->getTypeId() == Part::GeomCircle::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomEllipse::getClassTypeId() ) {
|
||||
auto solvext = std::static_pointer_cast<const Sketcher::SolverGeometryExtension>(
|
||||
geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock());
|
||||
|
||||
addelement(geoid, Sketcher::mid);
|
||||
addelement(geoid, Sketcher::none);
|
||||
}
|
||||
else if(geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) {
|
||||
|
||||
addelement(geoid, Sketcher::start);
|
||||
addelement(geoid, Sketcher::end);
|
||||
addelement(geoid, Sketcher::mid);
|
||||
addelement(geoid, Sketcher::none);
|
||||
if (solvext->getGeometry() == Sketcher::SolverGeometryExtension::NotFullyConstraint) {
|
||||
// The solver differentiates whether the parameters that are dependent are not those
|
||||
// of start, end, mid, and assigns them to the edge (edge params = curve params - parms of start, end, mid).
|
||||
// The user looking at the UI expects that the edge of a NotFullyConstraint geometry
|
||||
// will always move, even if the edge parameters are independent, for example if mid is
|
||||
// the only dependent parameter. In other words, the user could reasonably restrict the edge
|
||||
// to reach a fully constrained element. Under this understanding, the edge parameter would
|
||||
// always be dependent, unless the element is fully constrained.
|
||||
//
|
||||
// While this is ok from a user visual expectation point of view, it leads to a loss of information
|
||||
// of whether restricting the point start, end, mid that is dependent may suffice, or even if such
|
||||
// points are restricted, the edge would still need to be restricted.
|
||||
//
|
||||
// Because Python gets the information in this function, it would lead to Python users having access
|
||||
// to a lower amount of detail.
|
||||
//
|
||||
// For this reason, this function returns edge as dependent parameter if and only if constraining the
|
||||
// parameters of the points would not suffice to constraint the element.
|
||||
if (solvext->getEdge() == SolverGeometryExtension::Dependent)
|
||||
geometrymap.emplace_back(geoid,Sketcher::none);
|
||||
if (solvext->getStart() == SolverGeometryExtension::Dependent)
|
||||
geometrymap.emplace_back(geoid,Sketcher::start);
|
||||
if (solvext->getEnd() == SolverGeometryExtension::Dependent)
|
||||
geometrymap.emplace_back(geoid,Sketcher::start);
|
||||
if (solvext->getMid() == SolverGeometryExtension::Dependent)
|
||||
geometrymap.emplace_back(geoid,Sketcher::start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
geoid++;
|
||||
}
|
||||
|
||||
if(curQRAlg == GCS::EigenSparseQR) {
|
||||
getSolvedSketch().setQRAlgorithm(GCS::EigenSparseQR);
|
||||
}
|
||||
}
|
||||
|
||||
bool SketchObject::evaluateConstraint(const Constraint *constraint) const
|
||||
|
||||
@@ -511,8 +511,6 @@ private:
|
||||
bool internaltransaction;
|
||||
|
||||
bool managedoperation; // indicates whether changes to properties are the deed of SketchObject or not (for input validation)
|
||||
|
||||
bool deletinginternalgeometry; // sets a lock to deletinginternalgeometryoperation so that no individual triggers are perform on each element.
|
||||
};
|
||||
|
||||
typedef App::FeaturePythonT<SketchObject> SketchObjectPython;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2019 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Base/Exception.h>
|
||||
|
||||
#include "SolverGeometryExtension.h"
|
||||
|
||||
using namespace Sketcher;
|
||||
|
||||
|
||||
//---------- Geometry Extension
|
||||
TYPESYSTEM_SOURCE(Sketcher::SolverGeometryExtension,Part::GeometryExtension)
|
||||
|
||||
SolverGeometryExtension::SolverGeometryExtension():
|
||||
Edge(SolverGeometryExtension::Dependent),
|
||||
Start(SolverGeometryExtension::Dependent),
|
||||
Mid(SolverGeometryExtension::Dependent),
|
||||
End(SolverGeometryExtension::Dependent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<Part::GeometryExtension> SolverGeometryExtension::copy(void) const
|
||||
{
|
||||
auto cpy = std::make_unique<SolverGeometryExtension>();
|
||||
|
||||
cpy->Edge = this->Edge;
|
||||
cpy->Start = this->Start;
|
||||
cpy->End = this->End;
|
||||
cpy->Mid = this->Mid;
|
||||
|
||||
cpy->setName(this->getName()); // Base Class
|
||||
|
||||
#if defined (__GNUC__) && (__GNUC__ <=4)
|
||||
return std::move(cpy);
|
||||
#else
|
||||
return cpy;
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject * SolverGeometryExtension::getPyObject(void)
|
||||
{
|
||||
THROWM(Base::NotImplementedError, "SolverGeometryExtension does not have a Python counterpart");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2019 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef SKETCHER_SOLVERGEOMETRYEXTENSION_H
|
||||
#define SKETCHER_SOLVERGEOMETRYEXTENSION_H
|
||||
|
||||
#include <Mod/Part/App/GeometryExtension.h>
|
||||
|
||||
namespace Sketcher
|
||||
{
|
||||
|
||||
class SketcherExport SolverGeometryExtension : public Part::GeometryExtension
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
public:
|
||||
enum SolverStatus {
|
||||
FullyConstraint = 0,
|
||||
NotFullyConstraint = 1,
|
||||
NumSolverStatus
|
||||
};
|
||||
|
||||
enum ParameterStatus {
|
||||
Dependent = 0,
|
||||
Independent = 1,
|
||||
NumParameterStatus
|
||||
};
|
||||
|
||||
SolverGeometryExtension();
|
||||
SolverGeometryExtension(long cid);
|
||||
virtual ~SolverGeometryExtension() override = default;
|
||||
|
||||
virtual std::unique_ptr<Part::GeometryExtension> copy(void) const override;
|
||||
|
||||
virtual PyObject *getPyObject(void) override;
|
||||
|
||||
SolverStatus getGeometry() const {return ( Edge == Independent &&
|
||||
Start == Independent &&
|
||||
End == Independent &&
|
||||
Mid == Independent) ? FullyConstraint : NotFullyConstraint;}
|
||||
|
||||
ParameterStatus getEdge() const {return Edge;}
|
||||
void setEdge(ParameterStatus status) {Edge = status;}
|
||||
|
||||
ParameterStatus getStart() const {return Start;}
|
||||
void setStart(ParameterStatus status) {Start = status;}
|
||||
|
||||
ParameterStatus getMid() const {return Mid;}
|
||||
void setMid(ParameterStatus status) {Mid = status;}
|
||||
|
||||
ParameterStatus getEnd() const {return End;}
|
||||
void setEnd(ParameterStatus status) {End = status;}
|
||||
|
||||
void init(ParameterStatus status) {
|
||||
Edge = status;
|
||||
Start = status;
|
||||
Mid = status;
|
||||
End = status;
|
||||
}
|
||||
|
||||
private:
|
||||
SolverGeometryExtension(const SolverGeometryExtension&) = default;
|
||||
|
||||
private:
|
||||
ParameterStatus Edge;
|
||||
ParameterStatus Start;
|
||||
ParameterStatus Mid;
|
||||
ParameterStatus End;
|
||||
};
|
||||
|
||||
} //namespace Sketcher
|
||||
|
||||
|
||||
#endif // SKETCHER_SOLVERGEOMETRYEXTENSION_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,17 @@
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <boost/graph/graph_concepts.hpp>
|
||||
|
||||
#include <Eigen/QR>
|
||||
|
||||
#define EIGEN_VERSION (EIGEN_WORLD_VERSION * 10000 \
|
||||
+ EIGEN_MAJOR_VERSION * 100 \
|
||||
+ EIGEN_MINOR_VERSION)
|
||||
|
||||
#if EIGEN_VERSION >= 30202
|
||||
#define EIGEN_SPARSEQR_COMPATIBLE
|
||||
#include <Eigen/Sparse>
|
||||
#endif
|
||||
|
||||
namespace GCS
|
||||
{
|
||||
///////////////////////////////////////
|
||||
@@ -91,7 +102,11 @@ namespace GCS
|
||||
VEC_pD pdrivenlist; // list of parameters of driven constraints
|
||||
MAP_pD_I pIndex;
|
||||
|
||||
VEC_pD pdependentparameters; // list of dependent parameters by the system
|
||||
VEC_pD pDependentParameters; // list of dependent parameters by the system
|
||||
|
||||
// This is a map of primary and secondary identifiers that are found dependent by the solver
|
||||
// GCS ignores from a type point
|
||||
std::vector< std::set<double *> > pDependentParametersGroups;
|
||||
|
||||
std::vector<Constraint *> clist;
|
||||
std::map<Constraint *,VEC_pD > c2p; // constraint to parameter adjacency list
|
||||
@@ -116,12 +131,66 @@ namespace GCS
|
||||
bool hasDiagnosis; // if dofs, conflictingTags, redundantTags are up to date
|
||||
bool isInit; // if plists, clists, reductionmaps are up to date
|
||||
|
||||
bool emptyDiagnoseMatrix; // false only if there is at least one driving constraint.
|
||||
|
||||
int solve_BFGS(SubSystem *subsys, bool isFine=true, bool isRedundantsolving=false);
|
||||
int solve_LM(SubSystem *subsys, bool isRedundantsolving=false);
|
||||
int solve_DL(SubSystem *subsys, bool isRedundantsolving=false);
|
||||
|
||||
void makeReducedJacobian(Eigen::MatrixXd &J, std::map<int,int> &jacobianconstraintmap, GCS::VEC_pD &pdiagnoselist, std::map< int , int> &tagmultiplicity);
|
||||
|
||||
void makeDenseQRDecomposition( const Eigen::MatrixXd &J,
|
||||
const std::map<int,int> &jacobianconstraintmap,
|
||||
Eigen::FullPivHouseholderQR<Eigen::MatrixXd>& qrJT,
|
||||
int &rank, Eigen::MatrixXd &R, bool transposeJ = true, bool silent = false);
|
||||
|
||||
#ifdef EIGEN_SPARSEQR_COMPATIBLE
|
||||
void makeSparseQRDecomposition( const Eigen::MatrixXd &J,
|
||||
const std::map<int,int> &jacobianconstraintmap,
|
||||
Eigen::SparseQR<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int> > &SqrJT,
|
||||
int &rank, Eigen::MatrixXd &R, bool transposeJ = true, bool silent = false);
|
||||
#endif
|
||||
// This function name is long for a reason:
|
||||
// - Only for DenseQR
|
||||
// - Only for Transposed Jacobian QR decomposition
|
||||
void identifyDependentGeometryParametersInTransposedJacobianDenseQRDecomposition(
|
||||
const Eigen::FullPivHouseholderQR<Eigen::MatrixXd>& qrJT,
|
||||
const GCS::VEC_pD &pdiagnoselist,
|
||||
int paramsNum, int rank
|
||||
);
|
||||
|
||||
template <typename T>
|
||||
void identifyConflictingRedundantConstraints( Algorithm alg,
|
||||
const T & qrJT,
|
||||
const std::map<int,int> &jacobianconstraintmap,
|
||||
const std::map< int , int> &tagmultiplicity,
|
||||
GCS::VEC_pD &pdiagnoselist,
|
||||
Eigen::MatrixXd &R,
|
||||
int constrNum, int rank,
|
||||
int &nonredundantconstrNum
|
||||
);
|
||||
|
||||
void eliminateNonZerosOverPivotInUpperTriangularMatrix(Eigen::MatrixXd &R, int rank);
|
||||
|
||||
#ifdef EIGEN_SPARSEQR_COMPATIBLE
|
||||
void identifyDependentParametersSparseQR( const Eigen::MatrixXd &J,
|
||||
const std::map<int,int> &jacobianconstraintmap,
|
||||
const GCS::VEC_pD &pdiagnoselist,
|
||||
bool silent=true);
|
||||
#endif
|
||||
|
||||
void identifyDependentParametersDenseQR( const Eigen::MatrixXd &J,
|
||||
const std::map<int,int> &jacobianconstraintmap,
|
||||
const GCS::VEC_pD &pdiagnoselist,
|
||||
bool silent=true);
|
||||
|
||||
template <typename T>
|
||||
void identifyDependentParameters( T & qrJ,
|
||||
Eigen::MatrixXd &Rparams,
|
||||
int rank,
|
||||
const GCS::VEC_pD &pdiagnoselist,
|
||||
bool silent=true);
|
||||
|
||||
#ifdef _GCS_EXTRACT_SOLVER_SUBSYSTEM_
|
||||
void extractSubsystem(SubSystem *subsys, bool isRedundantsolving);
|
||||
#endif
|
||||
@@ -292,8 +361,11 @@ namespace GCS
|
||||
{ conflictingOut = hasDiagnosis ? conflictingTags : VEC_I(0); }
|
||||
void getRedundant(VEC_I &redundantOut) const
|
||||
{ redundantOut = hasDiagnosis ? redundantTags : VEC_I(0); }
|
||||
void getDependentParams(VEC_pD &pconstraintplistOut) const
|
||||
{ pconstraintplistOut = pdependentparameters;}
|
||||
void getDependentParams(VEC_pD &pdependentparameterlist) const
|
||||
{ pdependentparameterlist = pDependentParameters;}
|
||||
void getDependentParamsGroups(std::vector<std::set<double *>> &pdependentparametergroups) const
|
||||
{ pdependentparametergroups = pDependentParametersGroups;}
|
||||
bool isEmptyDiagnoseMatrix() const {return emptyDiagnoseMatrix;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -28,14 +28,7 @@
|
||||
|
||||
namespace GCS
|
||||
{
|
||||
class DependentParameters
|
||||
{
|
||||
public:
|
||||
DependentParameters():hasDependentParameters(false) {}
|
||||
bool hasDependentParameters;
|
||||
};
|
||||
|
||||
class Point : public DependentParameters
|
||||
class Point
|
||||
{
|
||||
public:
|
||||
Point(){x = 0; y = 0;}
|
||||
@@ -45,7 +38,7 @@ namespace GCS
|
||||
};
|
||||
|
||||
typedef std::vector<Point> VEC_P;
|
||||
|
||||
|
||||
///Class DeriVector2 holds a vector value and its derivative on the
|
||||
///parameter that the derivatives are being calculated for now. x,y is the
|
||||
///actual vector (v). dx,dy is a derivative of the vector by a parameter
|
||||
@@ -96,7 +89,7 @@ namespace GCS
|
||||
// Geometries
|
||||
///////////////////////////////////////
|
||||
|
||||
class Curve: public DependentParameters //a base class for all curve-based objects (line, circle/arc, ellipse/arc)
|
||||
class Curve //a base class for all curve-based objects (line, circle/arc, ellipse/arc)
|
||||
{
|
||||
public:
|
||||
virtual ~Curve(){}
|
||||
@@ -169,7 +162,7 @@ namespace GCS
|
||||
virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt);
|
||||
virtual Arc* Copy();
|
||||
};
|
||||
|
||||
|
||||
class MajorRadiusConic: public Curve
|
||||
{
|
||||
public:
|
||||
@@ -179,13 +172,13 @@ namespace GCS
|
||||
virtual double getRadMaj() = 0;
|
||||
DeriVector2 CalculateNormal(Point &p, double* derivparam = 0) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Ellipse: public MajorRadiusConic
|
||||
{
|
||||
public:
|
||||
Ellipse(){ radmin = 0;}
|
||||
virtual ~Ellipse(){}
|
||||
Point center;
|
||||
Point center;
|
||||
Point focus1;
|
||||
double *radmin;
|
||||
virtual double getRadMaj(const DeriVector2 ¢er, const DeriVector2 &f1, double b, double db, double &ret_dRadMaj);
|
||||
@@ -197,7 +190,7 @@ namespace GCS
|
||||
virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt);
|
||||
virtual Ellipse* Copy();
|
||||
};
|
||||
|
||||
|
||||
class ArcOfEllipse: public Ellipse
|
||||
{
|
||||
public:
|
||||
@@ -215,13 +208,13 @@ namespace GCS
|
||||
virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt);
|
||||
virtual ArcOfEllipse* Copy();
|
||||
};
|
||||
|
||||
|
||||
class Hyperbola: public MajorRadiusConic
|
||||
{
|
||||
public:
|
||||
Hyperbola(){ radmin = 0;}
|
||||
virtual ~Hyperbola(){}
|
||||
Point center;
|
||||
Point center;
|
||||
Point focus1;
|
||||
double *radmin;
|
||||
virtual double getRadMaj(const DeriVector2 ¢er, const DeriVector2 &f1, double b, double db, double &ret_dRadMaj);
|
||||
@@ -232,7 +225,7 @@ namespace GCS
|
||||
virtual int PushOwnParams(VEC_pD &pvec);
|
||||
virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt);
|
||||
virtual Hyperbola* Copy();
|
||||
};
|
||||
};
|
||||
|
||||
class ArcOfHyperbola: public Hyperbola
|
||||
{
|
||||
@@ -249,20 +242,20 @@ namespace GCS
|
||||
virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt);
|
||||
virtual ArcOfHyperbola* Copy();
|
||||
};
|
||||
|
||||
|
||||
class Parabola: public Curve
|
||||
{
|
||||
public:
|
||||
Parabola(){ }
|
||||
virtual ~Parabola(){}
|
||||
Point vertex;
|
||||
Point vertex;
|
||||
Point focus1;
|
||||
DeriVector2 CalculateNormal(Point &p, double* derivparam = 0);
|
||||
virtual DeriVector2 Value(double u, double du, double* derivparam = 0);
|
||||
virtual int PushOwnParams(VEC_pD &pvec);
|
||||
virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt);
|
||||
virtual Parabola* Copy();
|
||||
};
|
||||
};
|
||||
|
||||
class ArcOfParabola: public Parabola
|
||||
{
|
||||
@@ -306,7 +299,7 @@ namespace GCS
|
||||
virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt);
|
||||
virtual BSpline* Copy();
|
||||
};
|
||||
|
||||
|
||||
} //namespace GCS
|
||||
|
||||
#endif // PLANEGCS_GEO_H
|
||||
|
||||
@@ -260,11 +260,15 @@ bool SketcherGui::isBsplinePole(const Part::Geometry * geo)
|
||||
{
|
||||
auto gf = GeometryFacade::getFacade(geo);
|
||||
|
||||
return gf->getInternalType() == InternalType::BSplineControlPoint;
|
||||
if(gf)
|
||||
return gf->getInternalType() == InternalType::BSplineControlPoint;
|
||||
|
||||
THROWM(Base::ValueError, "Null geometry in isBsplinePole - please report")
|
||||
}
|
||||
|
||||
bool SketcherGui::isBsplinePole(const Sketcher::SketchObject* Obj, int GeoId)
|
||||
{
|
||||
|
||||
auto geom = Obj->getGeometry(GeoId);
|
||||
|
||||
return isBsplinePole(geom);
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
#include <Mod/Part/App/Geometry.h>
|
||||
#include <Mod/Sketcher/App/SketchObject.h>
|
||||
#include <Mod/Sketcher/App/SolverGeometryExtension.h>
|
||||
|
||||
#include "ViewProviderSketch.h"
|
||||
#include "SketchRectangularArrayDialog.h"
|
||||
@@ -739,69 +740,51 @@ void CmdSketcherSelectElementsWithDoFs::activated(int iMsg)
|
||||
|
||||
auto geos = Obj->getInternalGeometry();
|
||||
|
||||
// Solver parameter detection algorithm only works for Dense QR with full pivoting. If we are using Sparse QR, we
|
||||
// have to re-solve using Dense QR.
|
||||
GCS::QRAlgorithm curQRAlg = Obj->getSolvedSketch().getQRAlgorithm();
|
||||
|
||||
if (curQRAlg == GCS::EigenSparseQR) {
|
||||
Obj->getSolvedSketch().setQRAlgorithm(GCS::EigenDenseQR);
|
||||
Obj->solve(false);
|
||||
}
|
||||
|
||||
auto testselectvertex = [&Obj, &ss, &doc_name, &obj_name](int geoId, PointPos pos) {
|
||||
ss.str(std::string());
|
||||
|
||||
if (Obj->getSolvedSketch().hasDependentParameters(geoId, pos)) {
|
||||
int vertex = Obj->getVertexIndexGeoPos(geoId, pos);
|
||||
if (vertex > -1) {
|
||||
ss << "Vertex" << vertex + 1;
|
||||
int vertex = Obj->getVertexIndexGeoPos(geoId, pos);
|
||||
if (vertex > -1) {
|
||||
ss << "Vertex" << vertex + 1;
|
||||
|
||||
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
|
||||
}
|
||||
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
auto testselectedge = [&Obj, &ss, &doc_name, &obj_name](int geoId) {
|
||||
auto testselectedge = [&ss, &doc_name, &obj_name](int geoId) {
|
||||
ss.str(std::string());
|
||||
|
||||
if(Obj->getSolvedSketch().hasDependentParameters(geoId, Sketcher::none)) {
|
||||
ss << "Edge" << geoId + 1;
|
||||
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
|
||||
}
|
||||
ss << "Edge" << geoId + 1;
|
||||
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
|
||||
};
|
||||
|
||||
int geoid = 0;
|
||||
|
||||
for (auto geo : geos) {
|
||||
if (geo->getTypeId() == Part::GeomPoint::getClassTypeId()) {
|
||||
testselectvertex(geoid, Sketcher::start);
|
||||
}
|
||||
else if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) {
|
||||
testselectvertex(geoid, Sketcher::start);
|
||||
testselectvertex(geoid, Sketcher::end);
|
||||
testselectedge(geoid);
|
||||
}
|
||||
else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) {
|
||||
testselectvertex(geoid, Sketcher::mid);
|
||||
testselectedge(geoid);
|
||||
}
|
||||
else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() ||
|
||||
geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) {
|
||||
testselectvertex(geoid, Sketcher::start);
|
||||
testselectvertex(geoid, Sketcher::end);
|
||||
testselectvertex(geoid, Sketcher::mid);
|
||||
testselectedge(geoid);
|
||||
if(geo) {
|
||||
if(geo->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) {
|
||||
|
||||
auto solvext = std::static_pointer_cast<const Sketcher::SolverGeometryExtension>(
|
||||
geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock());
|
||||
|
||||
if (solvext->getGeometry() == Sketcher::SolverGeometryExtension::NotFullyConstraint) {
|
||||
// Coded for consistency with getGeometryWithDependentParameters, read the comments
|
||||
// on that function
|
||||
if (solvext->getEdge() == SolverGeometryExtension::Dependent)
|
||||
testselectedge(geoid);
|
||||
if (solvext->getStart() == SolverGeometryExtension::Dependent)
|
||||
testselectvertex(geoid, Sketcher::start);
|
||||
if (solvext->getEnd() == SolverGeometryExtension::Dependent)
|
||||
testselectvertex(geoid, Sketcher::end);
|
||||
if (solvext->getMid() == SolverGeometryExtension::Dependent)
|
||||
testselectvertex(geoid, Sketcher::mid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
geoid++;
|
||||
}
|
||||
|
||||
if (curQRAlg == GCS::EigenSparseQR) {
|
||||
Obj->getSolvedSketch().setQRAlgorithm(GCS::EigenSparseQR);
|
||||
}
|
||||
}
|
||||
|
||||
bool CmdSketcherSelectElementsWithDoFs::isActive(void)
|
||||
|
||||
@@ -261,6 +261,10 @@ void SketcherSettingsColors::saveSettings()
|
||||
ui->ExternalColor->onSave();
|
||||
ui->FullyConstrainedColor->onSave();
|
||||
ui->InternalAlignedGeoColor->onSave();
|
||||
ui->FullyConstraintElementColor->onSave();
|
||||
ui->FullyConstraintConstructionElementColor->onSave();
|
||||
ui->FullyConstraintInternalAlignmentColor->onSave();
|
||||
ui->FullyConstraintConstructionPointColor->onSave();
|
||||
|
||||
ui->ConstrainedColor->onSave();
|
||||
ui->NonDrivingConstraintColor->onSave();
|
||||
@@ -288,6 +292,10 @@ void SketcherSettingsColors::loadSettings()
|
||||
ui->ExternalColor->onRestore();
|
||||
ui->FullyConstrainedColor->onRestore();
|
||||
ui->InternalAlignedGeoColor->onRestore();
|
||||
ui->FullyConstraintElementColor->onRestore();
|
||||
ui->FullyConstraintConstructionElementColor->onRestore();
|
||||
ui->FullyConstraintInternalAlignmentColor->onRestore();
|
||||
ui->FullyConstraintConstructionPointColor->onRestore();
|
||||
|
||||
ui->ConstrainedColor->onRestore();
|
||||
ui->NonDrivingConstraintColor->onRestore();
|
||||
|
||||
@@ -320,6 +320,138 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_41">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fully constrained edit edge color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="FullyConstraintElementColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of fully constrained edge color in edit mode</string>
|
||||
</property>
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>128</red>
|
||||
<green>208</green>
|
||||
<blue>160</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>FullyConstraintElementColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>View</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_42">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fully constrained edit construction edge color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="FullyConstraintConstructionElementColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of fully constrained construction edge color in edit mode</string>
|
||||
</property>
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>143</red>
|
||||
<green>169</green>
|
||||
<blue>253</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>FullyConstraintConstructionElementColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>View</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_43">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fully constrained edit internal alignment edge color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="FullyConstraintInternalAlignmentColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of fully constrained internal alignment edge color in edit mode</string>
|
||||
</property>
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>222</red>
|
||||
<green>222</green>
|
||||
<blue>200</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>FullyConstraintInternalAlignmentColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>View</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_44">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>182</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fully constrained edit vertex color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="FullyConstraintConstructionPointColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of fully constrained vertex color in edit mode</string>
|
||||
</property>
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>255</red>
|
||||
<green>149</green>
|
||||
<blue>128</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>FullyConstraintConstructionPointColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>View</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -332,7 +464,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<item row="13" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="ConstrainedColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of driving constraints in edit mode</string>
|
||||
@@ -352,14 +484,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Reference constraint color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<item row="14" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="NonDrivingConstraintColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of reference constraints in edit mode</string>
|
||||
@@ -379,14 +511,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="15" column="0">
|
||||
<widget class="QLabel" name="labelexpr">
|
||||
<property name="text">
|
||||
<string>Expression dependent constraint color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<item row="15" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="ExprBasedConstrDimColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of expression dependent constraints in edit mode</string>
|
||||
@@ -406,14 +538,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<item row="16" column="0">
|
||||
<widget class="QLabel" name="labeldeact">
|
||||
<property name="text">
|
||||
<string>Deactivated constraint color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<item row="16" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DeactivatedConstrDimColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of deactivated constraints in edit mode</string>
|
||||
@@ -433,7 +565,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<item row="17" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -446,7 +578,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<item row="17" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="DatumColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of the datum portion of a driving constraint</string>
|
||||
@@ -466,7 +598,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<item row="18" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -479,7 +611,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<item row="18" column="1">
|
||||
<widget class="Gui::PrefSpinBox" name="SketcherDatumWidth">
|
||||
<property name="toolTip">
|
||||
<string>The default line thickness for new shapes</string>
|
||||
@@ -501,7 +633,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<item row="19" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -514,7 +646,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<item row="19" column="1">
|
||||
<widget class="Gui::PrefSpinBox" name="DefaultSketcherVertexWidth">
|
||||
<property name="toolTip">
|
||||
<string>The default line thickness for new shapes</string>
|
||||
@@ -536,7 +668,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0">
|
||||
<item row="20" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -549,7 +681,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<item row="20" column="1">
|
||||
<widget class="Gui::PrefSpinBox" name="DefaultSketcherLineWidth">
|
||||
<property name="toolTip">
|
||||
<string>The default line thickness for new shapes</string>
|
||||
@@ -571,7 +703,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="0">
|
||||
<item row="21" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -584,7 +716,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<item row="21" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="CursorTextColor">
|
||||
<property name="toolTip">
|
||||
<string>Text color of the coordinates</string>
|
||||
@@ -604,7 +736,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="0">
|
||||
<item row="22" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -617,7 +749,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<item row="22" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="CursorCrosshairColor">
|
||||
<property name="toolTip">
|
||||
<string>Color of crosshair cursor.
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
#include "TaskSketcherValidation.h"
|
||||
#include "CommandConstraints.h"
|
||||
#include "ViewProviderSketchGeometryExtension.h"
|
||||
#include <Mod/Sketcher/App/SolverGeometryExtension.h>
|
||||
|
||||
FC_LOG_LEVEL_INIT("Sketch",true,true)
|
||||
|
||||
@@ -143,24 +144,28 @@ using namespace SketcherGui;
|
||||
using namespace Sketcher;
|
||||
namespace bp = boost::placeholders;
|
||||
|
||||
SbColor ViewProviderSketch::VertexColor (1.0f,0.149f,0.0f); // #FF2600 -> (255, 38, 0)
|
||||
SbColor ViewProviderSketch::CurveColor (1.0f,1.0f,1.0f); // #FFFFFF -> (255,255,255)
|
||||
SbColor ViewProviderSketch::CurveDraftColor (0.0f,0.0f,0.86f); // #0000DC -> ( 0, 0,220)
|
||||
SbColor ViewProviderSketch::CurveExternalColor (0.8f,0.2f,0.6f); // #CC3399 -> (204, 51,153)
|
||||
SbColor ViewProviderSketch::CrossColorH (0.8f,0.4f,0.4f); // #CC6666 -> (204,102,102)
|
||||
SbColor ViewProviderSketch::CrossColorV (0.4f,0.8f,0.4f); // #66CC66 -> (102,204,102)
|
||||
SbColor ViewProviderSketch::FullyConstrainedColor (0.0f,1.0f,0.0f); // #00FF00 -> ( 0,255, 0)
|
||||
SbColor ViewProviderSketch::ConstrDimColor (1.0f,0.149f,0.0f); // #FF2600 -> (255, 38, 0)
|
||||
SbColor ViewProviderSketch::ConstrIcoColor (1.0f,0.149f,0.0f); // #FF2600 -> (255, 38, 0)
|
||||
SbColor ViewProviderSketch::NonDrivingConstrDimColor (0.0f,0.149f,1.0f); // #0026FF -> ( 0, 38,255)
|
||||
SbColor ViewProviderSketch::ExprBasedConstrDimColor (1.0f,0.5f,0.149f); // #FF7F26 -> (255, 127, 38)
|
||||
SbColor ViewProviderSketch::InformationColor (0.0f,1.0f,0.0f); // #00FF00 -> ( 0,255, 0)
|
||||
SbColor ViewProviderSketch::PreselectColor (0.88f,0.88f,0.0f); // #E1E100 -> (225,225, 0)
|
||||
SbColor ViewProviderSketch::SelectColor (0.11f,0.68f,0.11f); // #1CAD1C -> ( 28,173, 28)
|
||||
SbColor ViewProviderSketch::PreselectSelectedColor (0.36f,0.48f,0.11f); // #5D7B1C -> ( 93,123, 28)
|
||||
SbColor ViewProviderSketch::CreateCurveColor (0.8f,0.8f,0.8f); // #CCCCCC -> (204,204,204)
|
||||
SbColor ViewProviderSketch::DeactivatedConstrDimColor (0.8f,0.8f,0.8f); // #CCCCCC -> (204,204,204)
|
||||
SbColor ViewProviderSketch::InternalAlignedGeoColor (0.7f,0.7f,0.5f); // #B2B27F -> (178,178,127)
|
||||
SbColor ViewProviderSketch::VertexColor (1.0f,0.149f,0.0f); // #FF2600 -> (255, 38, 0)
|
||||
SbColor ViewProviderSketch::CurveColor (1.0f,1.0f,1.0f); // #FFFFFF -> (255,255,255)
|
||||
SbColor ViewProviderSketch::CurveDraftColor (0.0f,0.0f,0.86f); // #0000DC -> ( 0, 0,220)
|
||||
SbColor ViewProviderSketch::CurveExternalColor (0.8f,0.2f,0.6f); // #CC3399 -> (204, 51,153)
|
||||
SbColor ViewProviderSketch::CrossColorH (0.8f,0.4f,0.4f); // #CC6666 -> (204,102,102)
|
||||
SbColor ViewProviderSketch::CrossColorV (0.4f,0.8f,0.4f); // #66CC66 -> (102,204,102)
|
||||
SbColor ViewProviderSketch::FullyConstrainedColor (0.0f,1.0f,0.0f); // #00FF00 -> ( 0,255, 0)
|
||||
SbColor ViewProviderSketch::ConstrDimColor (1.0f,0.149f,0.0f); // #FF2600 -> (255, 38, 0)
|
||||
SbColor ViewProviderSketch::ConstrIcoColor (1.0f,0.149f,0.0f); // #FF2600 -> (255, 38, 0)
|
||||
SbColor ViewProviderSketch::NonDrivingConstrDimColor (0.0f,0.149f,1.0f); // #0026FF -> ( 0, 38,255)
|
||||
SbColor ViewProviderSketch::ExprBasedConstrDimColor (1.0f,0.5f,0.149f); // #FF7F26 -> (255, 127, 38)
|
||||
SbColor ViewProviderSketch::InformationColor (0.0f,1.0f,0.0f); // #00FF00 -> ( 0,255, 0)
|
||||
SbColor ViewProviderSketch::PreselectColor (0.88f,0.88f,0.0f); // #E1E100 -> (225,225, 0)
|
||||
SbColor ViewProviderSketch::SelectColor (0.11f,0.68f,0.11f); // #1CAD1C -> ( 28,173, 28)
|
||||
SbColor ViewProviderSketch::PreselectSelectedColor (0.36f,0.48f,0.11f); // #5D7B1C -> ( 93,123, 28)
|
||||
SbColor ViewProviderSketch::CreateCurveColor (0.8f,0.8f,0.8f); // #CCCCCC -> (204,204,204)
|
||||
SbColor ViewProviderSketch::DeactivatedConstrDimColor (0.8f,0.8f,0.8f); // #CCCCCC -> (204,204,204)
|
||||
SbColor ViewProviderSketch::InternalAlignedGeoColor (0.7f,0.7f,0.5f); // #B2B27F -> (178,178,127)
|
||||
SbColor ViewProviderSketch::FullyConstraintElementColor (0.50f,0.81f,0.62f); // #80D0A0 -> (128,208,160)
|
||||
SbColor ViewProviderSketch::FullyConstraintConstructionElementColor (0.56f,0.66f,0.99f); // #8FA9FD -> (143,169,253)
|
||||
SbColor ViewProviderSketch::FullyConstraintInternalAlignmentColor (0.87f,0.87f,0.78f); // #DEDEC8 -> (222,222,200)
|
||||
SbColor ViewProviderSketch::FullyConstraintConstructionPointColor (1.0f,0.58f,0.50f); // #FF9580 -> (255,149,128)
|
||||
// Variables for holding previous click
|
||||
SbTime ViewProviderSketch::prvClickTime;
|
||||
SbVec2s ViewProviderSketch::prvClickPos;
|
||||
@@ -1166,24 +1171,64 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor
|
||||
// This is because dragging gives unwanted cosmetic results due to the scale ratio.
|
||||
// This is an heuristic as it does not check all indirect routes.
|
||||
if(GeometryFacade::isInternalType(geo, InternalType::BSplineControlPoint)) {
|
||||
bool weight = false;
|
||||
bool weight_driven = false;
|
||||
bool equal = false;
|
||||
bool block = false;
|
||||
if(geo->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) {
|
||||
auto solvext = std::static_pointer_cast<const Sketcher::SolverGeometryExtension>(
|
||||
geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock());
|
||||
|
||||
// Edge parameters are Independent, so weight won't move
|
||||
if(solvext->getEdge()==Sketcher::SolverGeometryExtension::Independent) {
|
||||
Mode = STATUS_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The B-Spline is constrained to be non-rational (equal weights), moving produces a bad effect
|
||||
// because OCCT will normalize the values of the weights.
|
||||
auto grp = getSketchObject()->getSolvedSketch().getDependencyGroup(edit->DragCurve, Sketcher::none);
|
||||
|
||||
int bsplinegeoid = -1;
|
||||
|
||||
std::vector<int> polegeoids;
|
||||
|
||||
for( auto c : getSketchObject()->Constraints.getValues()) {
|
||||
if( c->Type == Sketcher::InternalAlignment &&
|
||||
c->AlignmentType == BSplineControlPoint &&
|
||||
c->First == edit->DragCurve ) {
|
||||
|
||||
bsplinegeoid = c->Second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(bsplinegeoid == -1) {
|
||||
Mode = STATUS_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
for( auto c : getSketchObject()->Constraints.getValues()) {
|
||||
if( c->Type == Sketcher::InternalAlignment &&
|
||||
c->AlignmentType == BSplineControlPoint &&
|
||||
c->Second == bsplinegeoid ) {
|
||||
|
||||
polegeoids.push_back(c->First);
|
||||
}
|
||||
}
|
||||
|
||||
bool allingroup = true;
|
||||
|
||||
for( auto polegeoid : polegeoids ) {
|
||||
std::pair< int, Sketcher::PointPos > thispole = std::make_pair(polegeoid,Sketcher::none);
|
||||
|
||||
if(grp.find(thispole) == grp.end()) // not found
|
||||
allingroup = false;
|
||||
}
|
||||
|
||||
if(allingroup) { // it is constrained to be non-rational
|
||||
Mode = STATUS_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(auto c : getSketchObject()->Constraints.getValues()) {
|
||||
weight = weight || (c->Type == Sketcher::Weight && c->First == edit->DragCurve);
|
||||
weight_driven = weight_driven || (c->Type == Sketcher::Weight && !c->isDriving && c->First == edit->DragCurve);
|
||||
equal = equal || (c->Type == Sketcher::Equal && (c->First == edit->DragCurve || c->Second == edit->DragCurve));
|
||||
block = block || (c->Type == Sketcher::Block && c->First == edit->DragCurve);
|
||||
}
|
||||
|
||||
if( (weight && !weight_driven) ||
|
||||
(equal && !weight_driven) ||
|
||||
block) {
|
||||
Mode = STATUS_NONE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
getSketchObject()->getSolvedSketch().initMove(edit->DragCurve, Sketcher::none, false);
|
||||
@@ -2756,6 +2801,22 @@ void ViewProviderSketch::updateColor(void)
|
||||
return false;
|
||||
};
|
||||
|
||||
auto isFullyConstraintElement = [](Sketcher::SketchObject* obj, int GeoId) -> bool {
|
||||
|
||||
const Part::Geometry* geom = obj->getGeometry(GeoId);
|
||||
|
||||
if(geom) {
|
||||
if(geom->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) {
|
||||
|
||||
auto solvext = std::static_pointer_cast<const Sketcher::SolverGeometryExtension>(
|
||||
geom->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock());
|
||||
|
||||
return (solvext->getGeometry() == Sketcher::SolverGeometryExtension::FullyConstraint);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// colors of the point set
|
||||
if (edit->FullyConstrained) {
|
||||
for (int i=0; i < PtNum; i++)
|
||||
@@ -2765,10 +2826,20 @@ void ViewProviderSketch::updateColor(void)
|
||||
for (int i=0; i < PtNum; i++) {
|
||||
int GeoId = edit->PointIdToGeoId[i];
|
||||
|
||||
if(isInternalAlignedGeom(getSketchObject(), GeoId))
|
||||
pcolor[i] = InternalAlignedGeoColor;
|
||||
else
|
||||
pcolor[i] = VertexColor;
|
||||
bool constrainedElement = isFullyConstraintElement(getSketchObject(), GeoId);
|
||||
|
||||
if(isInternalAlignedGeom(getSketchObject(), GeoId)) {
|
||||
if(constrainedElement)
|
||||
pcolor[i] = FullyConstraintInternalAlignmentColor;
|
||||
else
|
||||
pcolor[i] = InternalAlignedGeoColor;
|
||||
}
|
||||
else {
|
||||
if(constrainedElement)
|
||||
pcolor[i] = FullyConstraintConstructionPointColor;
|
||||
else
|
||||
pcolor[i] = VertexColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2820,6 +2891,8 @@ void ViewProviderSketch::updateColor(void)
|
||||
bool selected = (edit->SelCurvSet.find(GeoId) != edit->SelCurvSet.end());
|
||||
bool preselected = (edit->PreselectCurve == GeoId);
|
||||
|
||||
bool constrainedElement = isFullyConstraintElement(getSketchObject(), GeoId);
|
||||
|
||||
if (selected && preselected) {
|
||||
color[i] = PreselectSelectedColor;
|
||||
for (int k=j; j<k+indexes; j++) {
|
||||
@@ -2849,10 +2922,18 @@ void ViewProviderSketch::updateColor(void)
|
||||
}
|
||||
}
|
||||
else if (isConstructionGeom(getSketchObject(), GeoId)) {
|
||||
if(isInternalAlignedGeom(getSketchObject(), GeoId))
|
||||
color[i] = InternalAlignedGeoColor;
|
||||
else
|
||||
color[i] = CurveDraftColor;
|
||||
if(isInternalAlignedGeom(getSketchObject(), GeoId)) {
|
||||
if(constrainedElement)
|
||||
color[i] = FullyConstraintInternalAlignmentColor;
|
||||
else
|
||||
color[i] = InternalAlignedGeoColor;
|
||||
}
|
||||
else {
|
||||
if(constrainedElement)
|
||||
color[i] = FullyConstraintConstructionElementColor;
|
||||
else
|
||||
color[i] = CurveDraftColor;
|
||||
}
|
||||
|
||||
for (int k=j; j<k+indexes; j++) {
|
||||
verts[j].getValue(x,y,z);
|
||||
@@ -2866,6 +2947,13 @@ void ViewProviderSketch::updateColor(void)
|
||||
verts[j] = SbVec3f(x,y,zNormLine);
|
||||
}
|
||||
}
|
||||
else if (isFullyConstraintElement(getSketchObject(), GeoId)) {
|
||||
color[i] = FullyConstraintElementColor;
|
||||
for (int k=j; j<k+indexes; j++) {
|
||||
verts[j].getValue(x,y,z);
|
||||
verts[j] = SbVec3f(x,y,zNormLine);
|
||||
}
|
||||
}
|
||||
else {
|
||||
color[i] = CurveColor;
|
||||
for (int k=j; j<k+indexes; j++) {
|
||||
@@ -3769,6 +3857,16 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer
|
||||
Coords.emplace_back(x, y, 0);
|
||||
|
||||
// save scale factor for any prospective dragging operation
|
||||
// 1. Solver must be updated, in case a dragging operation starts
|
||||
// 2. if temp geometry is being used (with memory allocation), then the copy we have here must be updated. If
|
||||
// no temp geometry is being used, then the normal geometry must be updated.
|
||||
{// make solver be ready for a dragging operation
|
||||
auto vpext = std::make_unique<SketcherGui::ViewProviderSketchGeometryExtension>();
|
||||
vpext->setRepresentationFactor(scalefactor);
|
||||
|
||||
getSketchObject()->getSolvedSketch().updateExtension(GeoId, std::move(vpext));
|
||||
}
|
||||
|
||||
if(!circle->hasExtension(SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId()))
|
||||
{
|
||||
// It is ok to add this kind of extension to a const geometry because:
|
||||
@@ -6040,10 +6138,30 @@ bool ViewProviderSketch::setEdit(int ModNum)
|
||||
color = (unsigned long)(CurveDraftColor.getPackedValue());
|
||||
color = hGrp->GetUnsigned("ConstructionColor", color);
|
||||
CurveDraftColor.setPackedValue((uint32_t)color, transparency);
|
||||
// set the construction curve color
|
||||
// set the internal alignment geometry color
|
||||
color = (unsigned long)(InternalAlignedGeoColor.getPackedValue());
|
||||
color = hGrp->GetUnsigned("InternalAlignedGeoColor", color);
|
||||
InternalAlignedGeoColor.setPackedValue((uint32_t)color, transparency);
|
||||
// set the color for a fully constrained element
|
||||
color = (unsigned long)(FullyConstraintElementColor.getPackedValue());
|
||||
color = hGrp->GetUnsigned("FullyConstraintElementColor", color);
|
||||
FullyConstraintElementColor.setPackedValue((uint32_t)color, transparency);
|
||||
// set the color for fully constrained construction element
|
||||
color = (unsigned long)(FullyConstraintConstructionElementColor.getPackedValue());
|
||||
color = hGrp->GetUnsigned("FullyConstraintConstructionElementColor", color);
|
||||
FullyConstraintConstructionElementColor.setPackedValue((uint32_t)color, transparency);
|
||||
// set the color for fully constrained internal alignment element
|
||||
color = (unsigned long)(FullyConstraintInternalAlignmentColor.getPackedValue());
|
||||
color = hGrp->GetUnsigned("FullyConstraintInternalAlignmentColor", color);
|
||||
FullyConstraintInternalAlignmentColor.setPackedValue((uint32_t)color, transparency);
|
||||
// set the color for fully constrained construction points
|
||||
color = (unsigned long)(FullyConstraintConstructionPointColor.getPackedValue());
|
||||
color = hGrp->GetUnsigned("FullyConstraintConstructionPointColor", color);
|
||||
FullyConstraintConstructionPointColor.setPackedValue((uint32_t)color, transparency);
|
||||
// set fullyconstraint element color
|
||||
color = (unsigned long)(FullyConstraintElementColor.getPackedValue());
|
||||
color = hGrp->GetUnsigned("FullyConstraintElementColor", color);
|
||||
FullyConstraintElementColor.setPackedValue((uint32_t)color, transparency);
|
||||
// set the cross lines color
|
||||
//CrossColorV.setPackedValue((uint32_t)color, transparency);
|
||||
//CrossColorH.setPackedValue((uint32_t)color, transparency);
|
||||
@@ -6101,14 +6219,17 @@ bool ViewProviderSketch::setEdit(int ModNum)
|
||||
getSketchObject()->validateExternalLinks();
|
||||
}
|
||||
|
||||
// First drawing with non-temporal geometry, then updating solver information
|
||||
// This ensures that any ViewProvider geometry extension is set before the geometry
|
||||
// is loaded into the solver, which ensures that any prospective draw using temporal
|
||||
// geometry (draw with first parameter true) has the right ViewProvider geometry extensions
|
||||
// set - This fixes Weight constraint dragging on a just opened sketch.
|
||||
getSketchObject()->solve(false);
|
||||
UpdateSolverInformation();
|
||||
draw(false,true);
|
||||
// There are geometry extensions introduced by the solver and geometry extensions introduced by the viewprovider.
|
||||
// 1. It is important that the solver has geometry with updated extensions.
|
||||
// 2. It is important that the viewprovider has up-to-date solver information
|
||||
//
|
||||
// The decision is to maintain the "first solve then draw" order, which is consistent with the rest of the Sketcher
|
||||
// for example in geometry creation. Then, the ViewProvider is responsible for updating the solver geometry when
|
||||
// appropriate, as it is the ViewProvider that is introducing its geometry extensions.
|
||||
//
|
||||
// In order to have updated solver information, solve must take "true", this cause the Geometry property to be updated
|
||||
// with the solver information, including solver extensions, and triggers a draw(true) via ViewProvider::UpdateData.
|
||||
getSketchObject()->solve(true);
|
||||
|
||||
connectUndoDocument = getDocument()
|
||||
->signalUndoDocument.connect(boost::bind(&ViewProviderSketch::slotUndoDocument, this, bp::_1));
|
||||
|
||||
@@ -401,6 +401,10 @@ protected:
|
||||
static SbColor InformationColor;
|
||||
static SbColor DeactivatedConstrDimColor;
|
||||
static SbColor InternalAlignedGeoColor;
|
||||
static SbColor FullyConstraintElementColor;
|
||||
static SbColor FullyConstraintConstructionElementColor;
|
||||
static SbColor FullyConstraintInternalAlignmentColor;
|
||||
static SbColor FullyConstraintConstructionPointColor;
|
||||
|
||||
static SbTime prvClickTime;
|
||||
static SbVec2s prvClickPos; //used by double-click-detector
|
||||
|
||||
Reference in New Issue
Block a user