Draft Bezier Curve: implemented Continuity Property
Draft: allow continuity on closed Bezier curves Draft: BezCurve bugfixes - smoothBezCurve - edit mode - avoid splitting points into segments as long as degree is zero - increase the continuity when closing curve - closed berzier curves - Catch modifications of continuity of first and last knot on open curves
This commit is contained in:
parent
6f8c1c61b7
commit
2dfabfdcb5
|
@ -853,6 +853,7 @@ def makeBezCurve(pointslist,closed=False,placement=None,support=None,Degree=None
|
||||||
Part.BezierCurve().MaxDegree)
|
Part.BezierCurve().MaxDegree)
|
||||||
obj.Closed = closed
|
obj.Closed = closed
|
||||||
obj.Support = support
|
obj.Support = support
|
||||||
|
obj.Proxy.resetcontinuity(obj)
|
||||||
if placement: obj.Placement = placement
|
if placement: obj.Placement = placement
|
||||||
if gui:
|
if gui:
|
||||||
_ViewProviderWire(obj.ViewObject)
|
_ViewProviderWire(obj.ViewObject)
|
||||||
|
@ -3971,30 +3972,60 @@ class _BezCurve(_DraftObject):
|
||||||
"The points of the Bezier curve")
|
"The points of the Bezier curve")
|
||||||
obj.addProperty("App::PropertyInteger","Degree","Draft",
|
obj.addProperty("App::PropertyInteger","Degree","Draft",
|
||||||
"The degree of the Bezier function")
|
"The degree of the Bezier function")
|
||||||
|
obj.addProperty("App::PropertyIntegerList","Continuity","Draft",
|
||||||
|
"Continuity")
|
||||||
obj.addProperty("App::PropertyBool","Closed","Draft",
|
obj.addProperty("App::PropertyBool","Closed","Draft",
|
||||||
"If the Bezier curve should be closed or not")
|
"If the Bezier curve should be closed or not")
|
||||||
obj.Closed = False
|
obj.Closed = False
|
||||||
obj.Degree = 3
|
obj.Degree = 3
|
||||||
|
obj.Continuity = []
|
||||||
|
#obj.setEditorMode("Degree",2)#hide
|
||||||
|
obj.setEditorMode("Continuity",1)#ro
|
||||||
|
|
||||||
def execute(self, fp):
|
def execute(self, fp):
|
||||||
self.createGeometry(fp)
|
self.createGeometry(fp)
|
||||||
|
|
||||||
|
def _segpoleslst(self,fp):
|
||||||
|
"""split the points into segments"""
|
||||||
|
if not fp.Closed and len(fp.Points) >= 2: #allow lower degree segement
|
||||||
|
poles=fp.Points[1:]
|
||||||
|
elif fp.Closed and len(fp.Points) >= fp.Degree: #drawable
|
||||||
|
#poles=fp.Points[1:(fp.Degree*(len(fp.Points)//fp.Degree))]+fp.Points[0:1]
|
||||||
|
poles=fp.Points[1:]+fp.Points[0:1]
|
||||||
|
else:
|
||||||
|
poles=[]
|
||||||
|
return [poles[x:x+fp.Degree] for x in \
|
||||||
|
xrange(0, len(poles), (fp.Degree or 1))]
|
||||||
|
|
||||||
|
def resetcontinuity(self,fp):
|
||||||
|
fp.Continuity = [0]*(len(self._segpoleslst(fp))-1+1*fp.Closed)
|
||||||
|
#nump= len(fp.Points)-1+fp.Closed*1
|
||||||
|
#numsegments = (nump // fp.Degree) + 1 * (nump % fp.Degree > 0) -1
|
||||||
|
#fp.Continuity = [0]*numsegments
|
||||||
|
|
||||||
def onChanged(self, fp, prop):
|
def onChanged(self, fp, prop):
|
||||||
if prop in ["Points","Degree", "Closed"]:
|
if prop == 'Closed': # if remove the last entry when curve gets opened
|
||||||
|
oldlen = len(fp.Continuity)
|
||||||
|
newlen = (len(self._segpoleslst(fp))-1+1*fp.Closed)
|
||||||
|
if oldlen > newlen:
|
||||||
|
fp.Continuity = fp.Continuity[:newlen]
|
||||||
|
if oldlen < newlen:
|
||||||
|
fp.Continuity = fp.Continuity + [0]*(newlen-oldlen)
|
||||||
|
if hasattr(fp,'Closed') and fp.Closed and prop in ['Points','Degree','Closed'] and\
|
||||||
|
len(fp.Points) % fp.Degree: # the curve editing tools can't handle extra points
|
||||||
|
fp.Points=fp.Points[:(fp.Degree*(len(fp.Points)//fp.Degree))] #for closed curves
|
||||||
|
if prop in ["Degree"] and fp.Degree >= 1: #reset Continuity
|
||||||
|
self.resetcontinuity(fp)
|
||||||
|
if prop in ["Points","Degree","Continuity","Closed"]:
|
||||||
self.createGeometry(fp)
|
self.createGeometry(fp)
|
||||||
|
|
||||||
def createGeometry(self,fp):
|
def createGeometry(self,fp):
|
||||||
import Part
|
import Part
|
||||||
plm = fp.Placement
|
plm = fp.Placement
|
||||||
if fp.Points:
|
if fp.Points:
|
||||||
startpoint=fp.Points[0]
|
startpoint=fp.Points[0]
|
||||||
poles=fp.Points[1:]
|
|
||||||
if fp.Closed and (len(fp.Points) > 2):
|
|
||||||
poles.append(fp.Points[0])
|
|
||||||
segpoleslst=[poles[x:x+fp.Degree] for x in \
|
|
||||||
xrange(0, len(poles), fp.Degree)]
|
|
||||||
edges = []
|
edges = []
|
||||||
for segpoles in segpoleslst:
|
for segpoles in self._segpoleslst(fp):
|
||||||
# if len(segpoles) == fp.Degree # would skip additional poles
|
# if len(segpoles) == fp.Degree # would skip additional poles
|
||||||
c = Part.BezierCurve() #last segment may have lower degree
|
c = Part.BezierCurve() #last segment may have lower degree
|
||||||
c.increase(len(segpoles))
|
c.increase(len(segpoles))
|
||||||
|
|
|
@ -283,6 +283,7 @@ class DraftToolBar:
|
||||||
|
|
||||||
self.addButton = self._pushbutton("addButton", self.layout, icon="Draft_AddPoint", width=22, checkable=True)
|
self.addButton = self._pushbutton("addButton", self.layout, icon="Draft_AddPoint", width=22, checkable=True)
|
||||||
self.delButton = self._pushbutton("delButton", self.layout, icon="Draft_DelPoint", width=22, checkable=True)
|
self.delButton = self._pushbutton("delButton", self.layout, icon="Draft_DelPoint", width=22, checkable=True)
|
||||||
|
self.sharpButton = self._pushbutton("sharpButton", self.layout, icon="Draft_BezSharpNode", width=22, checkable=True)
|
||||||
self.tangentButton = self._pushbutton("tangentButton", self.layout, icon="Draft_BezTanNode", width=22, checkable=True)
|
self.tangentButton = self._pushbutton("tangentButton", self.layout, icon="Draft_BezTanNode", width=22, checkable=True)
|
||||||
self.symmetricButton = self._pushbutton("symmetricButton", self.layout, icon="Draft_BezSymNode", width=22, checkable=True)
|
self.symmetricButton = self._pushbutton("symmetricButton", self.layout, icon="Draft_BezSymNode", width=22, checkable=True)
|
||||||
|
|
||||||
|
@ -373,6 +374,7 @@ class DraftToolBar:
|
||||||
QtCore.QObject.connect(self.offsetValue,QtCore.SIGNAL("returnPressed()"),self.validatePoint)
|
QtCore.QObject.connect(self.offsetValue,QtCore.SIGNAL("returnPressed()"),self.validatePoint)
|
||||||
QtCore.QObject.connect(self.addButton,QtCore.SIGNAL("toggled(bool)"),self.setAddMode)
|
QtCore.QObject.connect(self.addButton,QtCore.SIGNAL("toggled(bool)"),self.setAddMode)
|
||||||
QtCore.QObject.connect(self.delButton,QtCore.SIGNAL("toggled(bool)"),self.setDelMode)
|
QtCore.QObject.connect(self.delButton,QtCore.SIGNAL("toggled(bool)"),self.setDelMode)
|
||||||
|
QtCore.QObject.connect(self.sharpButton,QtCore.SIGNAL("toggled(bool)"),self.setSharpMode)
|
||||||
QtCore.QObject.connect(self.tangentButton,QtCore.SIGNAL("toggled(bool)"),self.setTangentMode)
|
QtCore.QObject.connect(self.tangentButton,QtCore.SIGNAL("toggled(bool)"),self.setTangentMode)
|
||||||
QtCore.QObject.connect(self.symmetricButton,QtCore.SIGNAL("toggled(bool)"),self.setSymmetricMode)
|
QtCore.QObject.connect(self.symmetricButton,QtCore.SIGNAL("toggled(bool)"),self.setSymmetricMode)
|
||||||
QtCore.QObject.connect(self.finishButton,QtCore.SIGNAL("pressed()"),self.finish)
|
QtCore.QObject.connect(self.finishButton,QtCore.SIGNAL("pressed()"),self.finish)
|
||||||
|
@ -450,6 +452,7 @@ class DraftToolBar:
|
||||||
style = "#constrButton:Checked {background-color: "
|
style = "#constrButton:Checked {background-color: "
|
||||||
style += self.getDefaultColor("constr",rgb=True)+" } "
|
style += self.getDefaultColor("constr",rgb=True)+" } "
|
||||||
style += "#addButton:Checked, #delButton:checked, "
|
style += "#addButton:Checked, #delButton:checked, "
|
||||||
|
style += "#sharpButton:Checked, "
|
||||||
style += "#tangentButton:Checked, #symmetricButton:checked {"
|
style += "#tangentButton:Checked, #symmetricButton:checked {"
|
||||||
style += "background-color: rgb(20,100,250) }"
|
style += "background-color: rgb(20,100,250) }"
|
||||||
self.baseWidget.setStyleSheet(style)
|
self.baseWidget.setStyleSheet(style)
|
||||||
|
@ -482,6 +485,7 @@ class DraftToolBar:
|
||||||
self.occOffset.setText(translate("draft", "&OCC-style offset"))
|
self.occOffset.setText(translate("draft", "&OCC-style offset"))
|
||||||
self.addButton.setToolTip(translate("draft", "Add points to the current object"))
|
self.addButton.setToolTip(translate("draft", "Add points to the current object"))
|
||||||
self.delButton.setToolTip(translate("draft", "Remove points from the current object"))
|
self.delButton.setToolTip(translate("draft", "Remove points from the current object"))
|
||||||
|
self.sharpButton.setToolTip(translate("draft", "Make Bezier node sharp"))
|
||||||
self.tangentButton.setToolTip(translate("draft", "Make Bezier node tangent"))
|
self.tangentButton.setToolTip(translate("draft", "Make Bezier node tangent"))
|
||||||
self.symmetricButton.setToolTip(translate("draft", "Make Bezier node symmetric"))
|
self.symmetricButton.setToolTip(translate("draft", "Make Bezier node symmetric"))
|
||||||
self.undoButton.setText(translate("draft", "&Undo"))
|
self.undoButton.setText(translate("draft", "&Undo"))
|
||||||
|
@ -679,6 +683,7 @@ class DraftToolBar:
|
||||||
self.finishButton.hide()
|
self.finishButton.hide()
|
||||||
self.addButton.hide()
|
self.addButton.hide()
|
||||||
self.delButton.hide()
|
self.delButton.hide()
|
||||||
|
self.sharpButton.hide()
|
||||||
self.tangentButton.hide()
|
self.tangentButton.hide()
|
||||||
self.symmetricButton.hide()
|
self.symmetricButton.hide()
|
||||||
self.undoButton.hide()
|
self.undoButton.hide()
|
||||||
|
@ -810,6 +815,7 @@ class DraftToolBar:
|
||||||
self.addButton.show()
|
self.addButton.show()
|
||||||
self.delButton.show()
|
self.delButton.show()
|
||||||
if mode == 'BezCurve':
|
if mode == 'BezCurve':
|
||||||
|
self.sharpButton.show()
|
||||||
self.tangentButton.show()
|
self.tangentButton.show()
|
||||||
self.symmetricButton.show()
|
self.symmetricButton.show()
|
||||||
self.finishButton.show()
|
self.finishButton.show()
|
||||||
|
@ -817,6 +823,7 @@ class DraftToolBar:
|
||||||
# always start Edit with buttons unchecked
|
# always start Edit with buttons unchecked
|
||||||
self.addButton.setChecked(False)
|
self.addButton.setChecked(False)
|
||||||
self.delButton.setChecked(False)
|
self.delButton.setChecked(False)
|
||||||
|
self.sharpButton.setChecked(False)
|
||||||
self.tangentButton.setChecked(False)
|
self.tangentButton.setChecked(False)
|
||||||
self.symmetricButton.setChecked(False)
|
self.symmetricButton.setChecked(False)
|
||||||
|
|
||||||
|
@ -848,6 +855,7 @@ class DraftToolBar:
|
||||||
self.delButton.setEnabled(mode)
|
self.delButton.setEnabled(mode)
|
||||||
|
|
||||||
def setBezEditButtons(self,mode):
|
def setBezEditButtons(self,mode):
|
||||||
|
self.sharpButton.setEnabled(mode)
|
||||||
self.tangentButton.setEnabled(mode)
|
self.tangentButton.setEnabled(mode)
|
||||||
self.symmetricButton.setEnabled(mode)
|
self.symmetricButton.setEnabled(mode)
|
||||||
|
|
||||||
|
@ -1378,22 +1386,33 @@ class DraftToolBar:
|
||||||
if self.addButton.isChecked():
|
if self.addButton.isChecked():
|
||||||
self.delButton.setChecked(False)
|
self.delButton.setChecked(False)
|
||||||
self.symmetricButton.setChecked(False)
|
self.symmetricButton.setChecked(False)
|
||||||
|
self.sharpButton.setChecked(False)
|
||||||
self.tangentButton.setChecked(False)
|
self.tangentButton.setChecked(False)
|
||||||
|
|
||||||
def setDelMode(self,bool):
|
def setDelMode(self,bool):
|
||||||
if self.delButton.isChecked():
|
if self.delButton.isChecked():
|
||||||
self.addButton.setChecked(False)
|
self.addButton.setChecked(False)
|
||||||
self.symmetricButton.setChecked(False)
|
self.symmetricButton.setChecked(False)
|
||||||
|
self.sharpButton.setChecked(False)
|
||||||
self.tangentButton.setChecked(False)
|
self.tangentButton.setChecked(False)
|
||||||
|
|
||||||
|
def setSharpMode(self,bool):
|
||||||
|
if self.sharpButton.isChecked():
|
||||||
|
self.tangentButton.setChecked(False)
|
||||||
|
self.symmetricButton.setChecked(False)
|
||||||
|
self.addButton.setChecked(False)
|
||||||
|
self.delButton.setChecked(False)
|
||||||
|
|
||||||
def setTangentMode(self,bool):
|
def setTangentMode(self,bool):
|
||||||
if self.tangentButton.isChecked():
|
if self.tangentButton.isChecked():
|
||||||
|
self.sharpButton.setChecked(False)
|
||||||
self.symmetricButton.setChecked(False)
|
self.symmetricButton.setChecked(False)
|
||||||
self.addButton.setChecked(False)
|
self.addButton.setChecked(False)
|
||||||
self.delButton.setChecked(False)
|
self.delButton.setChecked(False)
|
||||||
|
|
||||||
def setSymmetricMode(self,bool):
|
def setSymmetricMode(self,bool):
|
||||||
if self.symmetricButton.isChecked():
|
if self.symmetricButton.isChecked():
|
||||||
|
self.sharpButton.setChecked(False)
|
||||||
self.tangentButton.setChecked(False)
|
self.tangentButton.setChecked(False)
|
||||||
self.addButton.setChecked(False)
|
self.addButton.setChecked(False)
|
||||||
self.delButton.setChecked(False)
|
self.delButton.setChecked(False)
|
||||||
|
|
|
@ -3319,6 +3319,10 @@ class Edit(Modifier):
|
||||||
if 'EditNode' in info["Component"]:
|
if 'EditNode' in info["Component"]:
|
||||||
self.delPoint(int(info["Component"][8:]))
|
self.delPoint(int(info["Component"][8:]))
|
||||||
# don't do tan/sym on DWire/BSpline!
|
# don't do tan/sym on DWire/BSpline!
|
||||||
|
elif ((Draft.getType(self.obj) == "BezCurve") and
|
||||||
|
(self.ui.sharpButton.isChecked())):
|
||||||
|
if 'EditNode' in info["Component"]:
|
||||||
|
self.smoothBezPoint(int(info["Component"][8:]), info, 'Sharp')
|
||||||
elif ((Draft.getType(self.obj) == "BezCurve") and
|
elif ((Draft.getType(self.obj) == "BezCurve") and
|
||||||
(self.ui.tangentButton.isChecked())):
|
(self.ui.tangentButton.isChecked())):
|
||||||
if 'EditNode' in info["Component"]:
|
if 'EditNode' in info["Component"]:
|
||||||
|
@ -3354,14 +3358,48 @@ class Edit(Modifier):
|
||||||
self.obj.Closed = True
|
self.obj.Closed = True
|
||||||
# DNC: fix error message if edited point coinsides with one of the existing points
|
# DNC: fix error message if edited point coinsides with one of the existing points
|
||||||
if ( editPnt in pts ) == False:
|
if ( editPnt in pts ) == False:
|
||||||
if Draft.getType(self.obj) in ["BezCurve"] and self.obj.Degree >=3 and \
|
if Draft.getType(self.obj) in ["BezCurve"]:
|
||||||
(self.editing % self.obj.Degree) == 0: #it's a knot
|
knot = None
|
||||||
if self.editing >= 1: #move left pole
|
ispole = self.editing % self.obj.Degree #
|
||||||
pts[self.editing-1] = pts[self.editing-1] + editPnt - pts[self.editing]
|
if ispole == 0: #knot
|
||||||
self.trackers[self.editing-1].set(pts[self.editing-1])
|
if self.obj.Degree >=3:
|
||||||
if self.editing < len(pts)-1: #move right pole
|
if self.editing >= 1: #move left pole
|
||||||
pts[self.editing+1] = pts[self.editing+1] + editPnt - pts[self.editing]
|
knotidx = self.editing if self.editing < len(pts) else 0
|
||||||
self.trackers[self.editing+1].set(pts[self.editing+1])
|
pts[self.editing-1] = pts[self.editing-1] + \
|
||||||
|
editPnt - pts[knotidx]
|
||||||
|
self.trackers[self.editing-1].set(\
|
||||||
|
pts[self.editing-1])
|
||||||
|
if self.editing < len(pts)-1: #move right pole
|
||||||
|
pts[self.editing+1] = pts[self.editing+1] + \
|
||||||
|
editPnt - pts[self.editing]
|
||||||
|
self.trackers[self.editing+1].set(\
|
||||||
|
pts[self.editing+1])
|
||||||
|
if self.editing == 0 and self.obj.Closed: # move last pole
|
||||||
|
pts[-1] = pts [-1] + editPnt -pts[self.editing]
|
||||||
|
self.trackers[-1].set(pts[-1])
|
||||||
|
elif ispole == 1 and (self.editing >=2 or self.obj.Closed): #right pole
|
||||||
|
knot = self.editing -1
|
||||||
|
changep = self.editing -2 # -1 in case of closed curve
|
||||||
|
elif ispole == self.obj.Degree-1 and \
|
||||||
|
self.editing <= len(pts)-3: #left pole
|
||||||
|
knot = self.editing +1
|
||||||
|
changep = self.editing +2
|
||||||
|
elif ispole == self.obj.Degree-1 and self.obj.Closed and \
|
||||||
|
self.editing == len(pts)-1: #last pole
|
||||||
|
knot = 0
|
||||||
|
changep = 1
|
||||||
|
if knot is not None: # we need to modify the oposite pole
|
||||||
|
segment = knot / self.obj.Degree -1
|
||||||
|
cont=self.obj.Continuity[segment] if \
|
||||||
|
len(self.obj.Continuity) > segment else 0
|
||||||
|
if cont == 1: #tangent
|
||||||
|
pts[changep] = self.obj.Proxy.modifytangentpole(\
|
||||||
|
pts[knot],editPnt,pts[changep])
|
||||||
|
self.trackers[changep].set(pts[changep])
|
||||||
|
elif cont ==2: #symmetric
|
||||||
|
pts[changep] = self.obj.Proxy.modifysymmetricpole(\
|
||||||
|
pts[knot],editPnt)
|
||||||
|
self.trackers[changep].set(pts[changep])
|
||||||
pts[self.editing] = editPnt
|
pts[self.editing] = editPnt
|
||||||
self.obj.Points = pts
|
self.obj.Points = pts
|
||||||
self.trackers[self.editing].set(v)
|
self.trackers[self.editing].set(v)
|
||||||
|
@ -3463,6 +3501,11 @@ class Edit(Modifier):
|
||||||
pts.extend(edge.Curve.getPoles()[1:])
|
pts.extend(edge.Curve.getPoles()[1:])
|
||||||
if self.obj.Closed:
|
if self.obj.Closed:
|
||||||
pts.pop()
|
pts.pop()
|
||||||
|
c=self.obj.Continuity
|
||||||
|
# assume we have a tangent continuity for an arbitrarily split
|
||||||
|
# segment, unless it's linear
|
||||||
|
cont = 1 if (self.obj.Degree >= 2) else 0
|
||||||
|
self.obj.Continuity = c[0:edgeindex]+[cont]+c[edgeindex:]
|
||||||
else:
|
else:
|
||||||
if ( Draft.getType(self.obj) == "Wire" ):
|
if ( Draft.getType(self.obj) == "Wire" ):
|
||||||
if (self.obj.Closed == True):
|
if (self.obj.Closed == True):
|
||||||
|
@ -3510,64 +3553,111 @@ class Edit(Modifier):
|
||||||
pts.pop(point)
|
pts.pop(point)
|
||||||
self.doc.openTransaction("Edit "+self.obj.Name)
|
self.doc.openTransaction("Edit "+self.obj.Name)
|
||||||
self.obj.Points = pts
|
self.obj.Points = pts
|
||||||
|
if Draft.getType(self.obj) =="BezCurve":
|
||||||
|
self.obj.Proxy.resetcontinuity(self.obj)
|
||||||
self.doc.commitTransaction()
|
self.doc.commitTransaction()
|
||||||
self.resetTrackers()
|
self.resetTrackers()
|
||||||
|
|
||||||
def smoothBezPoint(self,point, info=None, style='Symmetric'):
|
def smoothBezPoint(self,point, info=None, style='Symmetric'):
|
||||||
if not (Draft.getType(self.obj) == "BezCurve"): return
|
style2cont = {'Sharp':0,'Tangent':1,'Symmetric':2}
|
||||||
|
if not (Draft.getType(self.obj) == "BezCurve"):return
|
||||||
if info['Component'].startswith('Edge'):
|
if info['Component'].startswith('Edge'):
|
||||||
return # didn't click control point
|
return # didn't click control point
|
||||||
pts = self.obj.Points
|
pts = self.obj.Points
|
||||||
deg = self.obj.Degree
|
deg = self.obj.Degree
|
||||||
if point % deg != 0:
|
if deg < 2: return
|
||||||
|
if point % deg != 0: #point is a pole
|
||||||
if deg >=3: #allow to select poles
|
if deg >=3: #allow to select poles
|
||||||
if point > 2 and point % deg == 1: #right pole
|
if (point % deg == 1) and (point > 2 or self.obj.Closed): #right pole
|
||||||
knot = point -1
|
knot = point -1
|
||||||
keepp = point
|
keepp = point
|
||||||
changep = point -2
|
changep = point -2
|
||||||
elif point -3 < len(pts): #left pole
|
elif point < len(pts) -3 and point % deg == deg -1: #left pole
|
||||||
knot = point +1
|
knot = point +1
|
||||||
keepp = point
|
keepp = point
|
||||||
changep = point +2
|
changep = point +2
|
||||||
|
elif point == len(pts)-1 and self.obj.Closed: #last pole
|
||||||
|
# if the curve is closed the last pole has the last
|
||||||
|
# index in the poits lists
|
||||||
|
knot = 0
|
||||||
|
keepp = point
|
||||||
|
changep = 1
|
||||||
else:
|
else:
|
||||||
msg(translate("draft", "Can't change Knot belonging to that pole\n"),'warning')
|
msg(translate("draft", "Can't change Knot belonging to pole %d\n"%point)\
|
||||||
|
,'warning')
|
||||||
return
|
return
|
||||||
if knot:
|
if knot:
|
||||||
if style == 'Tangent':
|
if style == 'Tangent':
|
||||||
pts[changep] = self.obj.Proxy.modifytangentpole(pts[knot],pts[keepp],\
|
pts[changep] = self.obj.Proxy.modifytangentpole(\
|
||||||
pts[changep])
|
pts[knot],pts[keepp],pts[changep])
|
||||||
else:
|
elif style == 'Symmetric':
|
||||||
pts[changep] = self.obj.Proxy.modifysymmetricpole(pts[knot],pts[keepp])
|
pts[changep] = self.obj.Proxy.modifysymmetricpole(\
|
||||||
|
pts[knot],pts[keepp])
|
||||||
|
else: #sharp
|
||||||
|
pass #
|
||||||
else:
|
else:
|
||||||
msg(translate("draft", "Selection is not a Pole\n"),'warning')
|
msg(translate("draft", "Selection is not a Knot\n"),'warning')
|
||||||
return
|
return
|
||||||
elif (point == 0) or (point == (len(pts)-1)):
|
else: #point is a knot
|
||||||
msg(translate("draft", "Endpoint of BezCurve can't be smoothed\n"),'warning')
|
if style == 'Sharp':
|
||||||
return
|
if self.obj.Closed and point == len(pts)-1:
|
||||||
else:
|
knot = 0
|
||||||
if style == 'Tangent':
|
else:
|
||||||
|
knot = point
|
||||||
|
elif style == 'Tangent' and point > 0 and point < len(pts)-1:
|
||||||
prev, next = self.obj.Proxy.tangentpoles(pts[point],pts[point-1],pts[point+1])
|
prev, next = self.obj.Proxy.tangentpoles(pts[point],pts[point-1],pts[point+1])
|
||||||
else:
|
pts[point-1] = prev
|
||||||
|
pts[point+1] = next
|
||||||
|
knot = point #index for continuity
|
||||||
|
elif style == 'Symmetric' and point > 0 and point < len(pts)-1:
|
||||||
prev, next = self.obj.Proxy.symmetricpoles(pts[point],pts[point-1],pts[point+1])
|
prev, next = self.obj.Proxy.symmetricpoles(pts[point],pts[point-1],pts[point+1])
|
||||||
pts[point-1] = prev
|
pts[point-1] = prev
|
||||||
pts[point+1] = next
|
pts[point+1] = next
|
||||||
self.obj.Points = pts
|
knot = point #index for continuity
|
||||||
|
elif self.obj.Closed and (style == 'Symmetric' or style == 'Tangent'):
|
||||||
|
if style == 'Tangent':
|
||||||
|
pts[1],pts[-1] = self.obj.Proxy.tangentpoles(pts[0],pts[1],pts[-1])
|
||||||
|
elif style == 'Symmetric':
|
||||||
|
pts[1],pts[-1] = self.obj.Proxy.symmetricpoles(pts[0],pts[1],pts[-1])
|
||||||
|
knot = 0
|
||||||
|
else:
|
||||||
|
msg(translate("draft", "Endpoint of BezCurve can't be smoothed\n"),'warning')
|
||||||
|
return
|
||||||
|
segment = knot // deg #segment index
|
||||||
|
newcont=self.obj.Continuity[:] #dont edit a property inplace !!!
|
||||||
|
if not self.obj.Closed and (len(self.obj.Continuity) == segment -1 or \
|
||||||
|
segment == 0) : pass # open curve
|
||||||
|
elif len(self.obj.Continuity) >= segment or \
|
||||||
|
self.obj.Closed and segment == 0 and \
|
||||||
|
len(self.obj.Continuity) >1:
|
||||||
|
newcont[segment-1] = style2cont.get(style)
|
||||||
|
else: #should not happen
|
||||||
|
FreeCAD.Console.PrintWarning('Continuity indexing error:'+\
|
||||||
|
'point:%d deg:%d len(cont):%d' % (knot,deg,\
|
||||||
|
len(self.obj.Continuity)))
|
||||||
self.doc.openTransaction("Edit "+self.obj.Name)
|
self.doc.openTransaction("Edit "+self.obj.Name)
|
||||||
|
self.obj.Points = pts
|
||||||
|
self.obj.Continuity=newcont
|
||||||
self.doc.commitTransaction()
|
self.doc.commitTransaction()
|
||||||
self.resetTrackers()
|
self.resetTrackers()
|
||||||
|
|
||||||
def resetTrackersBezier(self):
|
def resetTrackersBezier(self):
|
||||||
knotmarker = coin.SoMarkerSet.SQUARE_FILLED_9_9
|
knotmarkers = (coin.SoMarkerSet.DIAMOND_FILLED_9_9,#sharp
|
||||||
polemarker = coin.SoMarkerSet.CIRCLE_FILLED_9_9
|
coin.SoMarkerSet.SQUARE_FILLED_9_9, #tangent
|
||||||
|
coin.SoMarkerSet.HOURGLASS_FILLED_9_9) #symmetric
|
||||||
|
polemarker = coin.SoMarkerSet.CIRCLE_FILLED_9_9 #pole
|
||||||
self.trackers=[]
|
self.trackers=[]
|
||||||
|
cont=self.obj.Continuity
|
||||||
|
firstknotcont = cont[-1] if (self.obj.Closed and cont) else 0
|
||||||
pointswithmarkers=[(self.obj.Shape.Edges[0].Curve.\
|
pointswithmarkers=[(self.obj.Shape.Edges[0].Curve.\
|
||||||
getPole(1),knotmarker)]
|
getPole(1),knotmarkers[firstknotcont])]
|
||||||
for edgeindex, edge in enumerate(self.obj.Shape.Edges):
|
for edgeindex, edge in enumerate(self.obj.Shape.Edges):
|
||||||
poles=edge.Curve.getPoles()
|
poles=edge.Curve.getPoles()
|
||||||
pointswithmarkers.extend([(point,polemarker) for \
|
pointswithmarkers.extend([(point,polemarker) for \
|
||||||
point in poles[1:-1]])
|
point in poles[1:-1]])
|
||||||
if not self.obj.Closed or len(self.obj.Shape.Edges) > edgeindex +1:
|
if not self.obj.Closed or len(self.obj.Shape.Edges) > edgeindex +1:
|
||||||
pointswithmarkers.append((poles[-1],knotmarker))
|
knotmarkeri=cont[edgeindex] if len(cont) > edgeindex else 0
|
||||||
|
pointswithmarkers.append((poles[-1],knotmarkers[knotmarkeri]))
|
||||||
for index,pwm in enumerate(pointswithmarkers):
|
for index,pwm in enumerate(pointswithmarkers):
|
||||||
p,marker=pwm
|
p,marker=pwm
|
||||||
if self.pl: p = self.pl.multVec(p)
|
if self.pl: p = self.pl.multVec(p)
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -6,6 +6,7 @@
|
||||||
<file>icons/Draft_Arc.svg</file>
|
<file>icons/Draft_Arc.svg</file>
|
||||||
<file>icons/Draft_BSpline.svg</file>
|
<file>icons/Draft_BSpline.svg</file>
|
||||||
<file>icons/Draft_BezCurve.svg</file>
|
<file>icons/Draft_BezCurve.svg</file>
|
||||||
|
<file>icons/Draft_BezSharpNode.svg</file>
|
||||||
<file>icons/Draft_BezTanNode.svg</file>
|
<file>icons/Draft_BezTanNode.svg</file>
|
||||||
<file>icons/Draft_BezSymNode.svg</file>
|
<file>icons/Draft_BezSymNode.svg</file>
|
||||||
<file>icons/Draft_Circle.svg</file>
|
<file>icons/Draft_Circle.svg</file>
|
||||||
|
|
304
src/Mod/Draft/Resources/icons/Draft_BezSharpNode.svg
Normal file
304
src/Mod/Draft/Resources/icons/Draft_BezSharpNode.svg
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
version="1.1"
|
||||||
|
width="64"
|
||||||
|
height="64"
|
||||||
|
id="svg3612">
|
||||||
|
<defs
|
||||||
|
id="defs3614">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3144-6">
|
||||||
|
<stop
|
||||||
|
id="stop3146-9"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3148-2"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3701">
|
||||||
|
<stop
|
||||||
|
id="stop3703"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3705"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="225.26402"
|
||||||
|
cy="672.79736"
|
||||||
|
r="34.345188"
|
||||||
|
fx="225.26402"
|
||||||
|
fy="672.79736"
|
||||||
|
id="radialGradient3688"
|
||||||
|
xlink:href="#linearGradient3144-6"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3708">
|
||||||
|
<stop
|
||||||
|
id="stop3710"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3712"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3864-0-0">
|
||||||
|
<stop
|
||||||
|
id="stop3866-5-7"
|
||||||
|
style="stop-color:#0619c0;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3868-7-6"
|
||||||
|
style="stop-color:#379cfb;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3377">
|
||||||
|
<stop
|
||||||
|
id="stop3379"
|
||||||
|
style="stop-color:#ffaa00;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3381"
|
||||||
|
style="stop-color:#faff2b;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3864-0">
|
||||||
|
<stop
|
||||||
|
id="stop3866-5"
|
||||||
|
style="stop-color:#0619c0;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3868-7"
|
||||||
|
style="stop-color:#379cfb;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient5048">
|
||||||
|
<stop
|
||||||
|
id="stop5050"
|
||||||
|
style="stop-color:#000000;stop-opacity:0"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop5056"
|
||||||
|
style="stop-color:#000000;stop-opacity:1"
|
||||||
|
offset="0.5" />
|
||||||
|
<stop
|
||||||
|
id="stop5052"
|
||||||
|
style="stop-color:#000000;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3841-0-3">
|
||||||
|
<stop
|
||||||
|
id="stop3843-1-3"
|
||||||
|
style="stop-color:#0619c0;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3845-0-8"
|
||||||
|
style="stop-color:#379cfb;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="20.892099"
|
||||||
|
cy="114.5684"
|
||||||
|
r="5.256"
|
||||||
|
fx="20.892099"
|
||||||
|
fy="114.5684"
|
||||||
|
id="aigrd2"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
id="stop15566"
|
||||||
|
style="stop-color:#f0f0f0;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop15568"
|
||||||
|
style="stop-color:#9a9a9a;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</radialGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="20.892099"
|
||||||
|
cy="64.567902"
|
||||||
|
r="5.257"
|
||||||
|
fx="20.892099"
|
||||||
|
fy="64.567902"
|
||||||
|
id="aigrd3"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
id="stop15573"
|
||||||
|
style="stop-color:#f0f0f0;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop15575"
|
||||||
|
style="stop-color:#9a9a9a;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</radialGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient15662">
|
||||||
|
<stop
|
||||||
|
id="stop15664"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop15666"
|
||||||
|
style="stop-color:#f8f8f8;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="33.966679"
|
||||||
|
cy="35.736916"
|
||||||
|
r="86.70845"
|
||||||
|
fx="33.966679"
|
||||||
|
fy="35.736916"
|
||||||
|
id="radialGradient4452"
|
||||||
|
xlink:href="#linearGradient259"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.96049297,0,0,1.041132,-52.144249,-702.33158)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient259">
|
||||||
|
<stop
|
||||||
|
id="stop260"
|
||||||
|
style="stop-color:#fafafa;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop261"
|
||||||
|
style="stop-color:#bbbbbb;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="8.824419"
|
||||||
|
cy="3.7561285"
|
||||||
|
r="37.751713"
|
||||||
|
fx="8.824419"
|
||||||
|
fy="3.7561285"
|
||||||
|
id="radialGradient4454"
|
||||||
|
xlink:href="#linearGradient269"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.96827297,0,0,1.032767,-48.790699,-701.68513)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient269">
|
||||||
|
<stop
|
||||||
|
id="stop270"
|
||||||
|
style="stop-color:#a3a3a3;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop271"
|
||||||
|
style="stop-color:#4c4c4c;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4095">
|
||||||
|
<stop
|
||||||
|
id="stop4097"
|
||||||
|
style="stop-color:#005bff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4099"
|
||||||
|
style="stop-color:#c1e3f7;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
x1="394.15784"
|
||||||
|
y1="185.1304"
|
||||||
|
x2="434.73947"
|
||||||
|
y2="140.22731"
|
||||||
|
id="linearGradient4253"
|
||||||
|
xlink:href="#linearGradient4247"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.94231826,0,0,0.94231826,23.727549,8.8262536)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4247">
|
||||||
|
<stop
|
||||||
|
id="stop4249"
|
||||||
|
style="stop-color:#2e8207;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4251"
|
||||||
|
style="stop-color:#52ff00;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="225.26402"
|
||||||
|
cy="672.79736"
|
||||||
|
r="34.345188"
|
||||||
|
fx="225.26402"
|
||||||
|
fy="672.79736"
|
||||||
|
id="radialGradient4317"
|
||||||
|
xlink:href="#linearGradient3144-8"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3144-8">
|
||||||
|
<stop
|
||||||
|
id="stop3146-96"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3148-4"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<metadata
|
||||||
|
id="metadata3617">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
d="M 7.090909,5.8181818 C 15.272728,20 -3.7471829,48.338335 31.636364,48.363637 61.272846,26.482175 48.000001,19.757576 56.181819,5.4545454 l 0,0"
|
||||||
|
id="path3179"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<path
|
||||||
|
d="M 6,48 31.560197,48.181818 61.382433,24.261076"
|
||||||
|
id="path3082"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<g
|
||||||
|
transform="matrix(-0.11387155,-0.09751677,0.09751677,-0.11387155,-9.9749576,141.51281)"
|
||||||
|
id="g4248">
|
||||||
|
<path
|
||||||
|
d="m 245.71428,655.2193 a 48.57143,48.57143 0 1 1 -97.14286,0 48.57143,48.57143 0 1 1 97.14286,0 z"
|
||||||
|
id="path4250"
|
||||||
|
style="fill:#0048ff;fill-opacity:1;stroke:#000000;stroke-width:5.80000019;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<path
|
||||||
|
d="m 259.60921,672.79736 a 34.34519,23.991124 0 1 1 -68.69038,0 34.34519,23.991124 0 1 1 68.69038,0 z"
|
||||||
|
transform="matrix(0.8513023,-0.5246754,0.5246754,0.8513023,-338.69692,214.19328)"
|
||||||
|
id="path4252"
|
||||||
|
style="fill:url(#radialGradient4317);fill-opacity:1;stroke:none" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
d="m -28.545455,43.545456 a 1.727273,1.727273 0 1 1 -3.454546,0 1.727273,1.727273 0 1 1 3.454546,0 z"
|
||||||
|
transform="translate(36.727273,4.3636364)"
|
||||||
|
id="path3084"
|
||||||
|
style="color:#000000;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
d="m 62.574703,24.99591 a 1.727273,1.727273 0 0 1 -3.454546,0 1.727273,1.727273 0 1 1 3.454546,0 z"
|
||||||
|
id="path3084-5"
|
||||||
|
style="color:#000000;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 9.5 KiB |
Loading…
Reference in New Issue
Block a user