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:
Sebastian Hoogen 2014-02-02 18:22:27 +01:00 committed by Yorik van Havre
parent 6f8c1c61b7
commit 2dfabfdcb5
6 changed files with 491 additions and 55039 deletions

View File

@ -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))

View File

@ -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)

View File

@ -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

View File

@ -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>

View 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