Add Draft Bezier Curve draw & edit mockup using bSpline tools.
This commit is contained in:
committed by
Yorik van Havre
parent
7eb7591a58
commit
2d43d61b92
@@ -830,7 +830,33 @@ def makeBSpline(pointslist,closed=False,placement=None,face=True,support=None):
|
||||
select(obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
return obj
|
||||
|
||||
#######################################
|
||||
def makeBezCurve(pointslist,placement=None,support=None):
|
||||
'''makeBezCurve(pointslist,[closed],[placement]): Creates a Bezier Curve object
|
||||
from the given list of vectors. Instead of a pointslist, you can also pass a Part Wire.'''
|
||||
if not isinstance(pointslist,list):
|
||||
nlist = []
|
||||
for v in pointslist.Vertexes:
|
||||
nlist.append(v.Point)
|
||||
pointslist = nlist
|
||||
if placement: typecheck([(placement,FreeCAD.Placement)], "makeBezCurve")
|
||||
if len(pointslist) == 2: fname = "Line"
|
||||
else: fname = "BezCurve"
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",fname)
|
||||
_BezCurve(obj)
|
||||
obj.Points = pointslist
|
||||
# obj.Closed = closed
|
||||
obj.Support = support
|
||||
if placement: obj.Placement = placement
|
||||
if gui:
|
||||
_ViewProviderWire(obj.ViewObject)
|
||||
# if not face: obj.ViewObject.DisplayMode = "Wireframe"
|
||||
obj.ViewObject.DisplayMode = "Wireframe"
|
||||
formatObject(obj)
|
||||
select(obj)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
return obj
|
||||
#######################################
|
||||
def makeText(stringslist,point=Vector(0,0,0),screen=False):
|
||||
'''makeText(strings,[point],[screen]): Creates a Text object at the given point,
|
||||
containing the strings given in the strings list, one string by line (strings
|
||||
@@ -3929,7 +3955,52 @@ class _BSpline(_DraftObject):
|
||||
|
||||
# for compatibility with older versions
|
||||
_ViewProviderBSpline = _ViewProviderWire
|
||||
#######################################
|
||||
class _BezCurve(_DraftObject):
|
||||
"The BezCurve object"
|
||||
|
||||
def __init__(self, obj):
|
||||
_DraftObject.__init__(self,obj,"BezCurve")
|
||||
obj.addProperty("App::PropertyVectorList","Points","Draft",
|
||||
"The points of the Bezier curve")
|
||||
# obj.addProperty("App::PropertyBool","Closed","Draft",
|
||||
# "If the Bezier curve is closed or not")
|
||||
obj.addProperty("App::PropertyInteger","Degree","Draft",
|
||||
"The degree of the Bezier function")
|
||||
obj.addProperty("App::PropertyBool","Closed","Draft",
|
||||
"If the Bezier curve is closed or not(??)")
|
||||
obj.Closed = False
|
||||
obj.Degree = 3
|
||||
|
||||
def execute(self, fp):
|
||||
self.createGeometry(fp)
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
if prop in ["Points","Degree"]:
|
||||
self.createGeometry(fp)
|
||||
|
||||
def createGeometry(self,fp):
|
||||
import Part
|
||||
plm = fp.Placement
|
||||
if fp.Points:
|
||||
# if fp.Points[0] == fp.Points[-1]:
|
||||
# if not fp.Closed: fp.Closed = True
|
||||
# fp.Points.pop()
|
||||
# if fp.Closed and (len(fp.Points) > 2):
|
||||
c = Part.BezierCurve()
|
||||
c.setPoles(fp.Points)
|
||||
e = Part.Edge(c)
|
||||
w = Part.Wire(e)
|
||||
fp.Shape = w
|
||||
# else:
|
||||
# spline = Part.BezCurveCurve()
|
||||
# spline.interpolate(fp.Points, False)
|
||||
# fp.Shape = spline.toShape()
|
||||
fp.Placement = plm
|
||||
|
||||
# for compatibility with older versions ???????
|
||||
_ViewProviderBezCurve = _ViewProviderWire
|
||||
#######################################
|
||||
class _Block(_DraftObject):
|
||||
"The Block object"
|
||||
|
||||
|
||||
@@ -1418,7 +1418,7 @@ class DraftToolBar:
|
||||
"Draft_Rectangle","Draft_Arc",
|
||||
"Draft_Circle","Draft_BSpline",
|
||||
"Draft_Text","Draft_Dimension",
|
||||
"Draft_ShapeString"]
|
||||
"Draft_ShapeString","Draft_BezCurve"]
|
||||
self.title = "Create objects"
|
||||
def shouldShow(self):
|
||||
return (FreeCAD.ActiveDocument != None) and (not FreeCADGui.Selection.getSelection())
|
||||
|
||||
@@ -665,7 +665,113 @@ class BSpline(Line):
|
||||
if self.ui:
|
||||
if self.ui.continueMode:
|
||||
self.Activated()
|
||||
#######################################
|
||||
class BezCurve(Line):
|
||||
"a FreeCAD command for creating a Bezier Curve"
|
||||
|
||||
def __init__(self):
|
||||
Line.__init__(self,wiremode=True)
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Draft_BezCurve',
|
||||
'Accel' : "B, Z",
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_BezCurve", "BezCurve"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_BezCurve", "Creates a Bezier curve. CTRL to snap, SHIFT to constrain")}
|
||||
|
||||
def Activated(self):
|
||||
Line.Activated(self,name=translate("draft","BezCurve"))
|
||||
if self.doc:
|
||||
self.bezcurvetrack = bezcurveTracker()
|
||||
|
||||
def action(self,arg):
|
||||
"scene event handler"
|
||||
if arg["Type"] == "SoKeyboardEvent":
|
||||
if arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
|
||||
self.point,ctrlPoint,info = getPoint(self,arg,noTracker=True)
|
||||
self.bezcurvetrack.update(self.node + [self.point]) #existing points + this pointer position
|
||||
elif arg["Type"] == "SoMouseButtonEvent":
|
||||
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): #left click
|
||||
if (arg["Position"] == self.pos): #double click?
|
||||
self.finish(False,cont=True)
|
||||
else:
|
||||
if (not self.node) and (not self.support): #first point
|
||||
self.support = getSupport(arg)
|
||||
if self.point:
|
||||
self.ui.redraw()
|
||||
self.pos = arg["Position"]
|
||||
self.node.append(self.point) #add point to "clicked list"
|
||||
# sb add a control point, if mod(len(cpoints),2) == 0) then create 2 handle points?
|
||||
self.drawUpdate(self.point) #???
|
||||
if (not self.isWire and len(self.node) == 2):
|
||||
self.finish(False,cont=True)
|
||||
if (len(self.node) > 2): #does this make sense for a BCurve?
|
||||
# DNC: allows to close the curve
|
||||
# by placing ends close to each other
|
||||
# with tol = Draft tolerance
|
||||
# old code has been to insensitive
|
||||
if ((self.point-self.node[0]).Length < Draft.tolerance()):
|
||||
self.undolast()
|
||||
self.finish(True,cont=True)
|
||||
msg(translate("draft", "Bezier curve has been closed\n"))
|
||||
|
||||
def undolast(self):
|
||||
"undoes last line segment"
|
||||
### this won't work exactly the same way for Bcurve????
|
||||
if (len(self.node) > 1):
|
||||
self.node.pop()
|
||||
self.bezcurvetrack.update(self.node)
|
||||
### self.obj.Shape.Edge[0].Curve.removePole(???)
|
||||
# c = Part.BezierCurve()
|
||||
# c.setPoles(self.Points)
|
||||
# e = Part.Edge(c)
|
||||
# w = Part.Wire(e)
|
||||
## spline = Part.bSplineCurve()
|
||||
## spline.interpolate(self.node, False)
|
||||
## self.obj.Shape = spline.toShape()
|
||||
# self.obj.Shape = w
|
||||
msg(translate("draft", "BezCurve sb undoing last segment\n"))
|
||||
msg(translate("draft", "Last point has been removed\n"))
|
||||
|
||||
def drawUpdate(self,point):
|
||||
msg(translate("draft", "BezCurve drawUpdate\n"))
|
||||
if (len(self.node) == 1):
|
||||
self.bezcurvetrack.on()
|
||||
if self.planetrack:
|
||||
self.planetrack.set(self.node[0])
|
||||
msg(translate("draft", "Pick next point:\n"))
|
||||
else:
|
||||
c = Part.BezierCurve()
|
||||
c.setPoles(self.node)
|
||||
e = Part.Edge(c)
|
||||
w = Part.Wire(e)
|
||||
self.obj.Shape = w
|
||||
msg(translate("draft", "Pick next point, or (F)inish or (C)lose:\n"))
|
||||
|
||||
def finish(self,closed=False,cont=False):
|
||||
"terminates the operation and closes the poly if asked"
|
||||
if self.ui:
|
||||
self.bezcurvetrack.finalize()
|
||||
if not Draft.getParam("UiMode",1):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
if (len(self.node) > 1):
|
||||
old = self.obj.Name
|
||||
todo.delay(self.doc.removeObject,old)
|
||||
try:
|
||||
# building command string
|
||||
rot,sup,pts,fil = self.getStrings()
|
||||
self.commit(translate("draft","Create BezCurve"),
|
||||
['import Draft',
|
||||
'points='+pts,
|
||||
'Draft.makeBezCurve(points,support='+sup+')'])
|
||||
except:
|
||||
print "Draft: error delaying commit"
|
||||
Creator.finish(self)
|
||||
if self.ui:
|
||||
if self.ui.continueMode:
|
||||
self.Activated()
|
||||
#######################################
|
||||
|
||||
class FinishLine:
|
||||
"a FreeCAD command to finish any running Line drawing operation"
|
||||
@@ -3093,7 +3199,7 @@ class Edit(Modifier):
|
||||
if hasattr(self.obj.ViewObject,"Selectable"):
|
||||
self.selectstate = self.obj.ViewObject.Selectable
|
||||
self.obj.ViewObject.Selectable = False
|
||||
if Draft.getType(self.obj) in ["Wire","BSpline"]:
|
||||
if Draft.getType(self.obj) in ["Wire","BSpline","BezCurve"]:
|
||||
self.ui.setEditButtons(True)
|
||||
else:
|
||||
self.ui.setEditButtons(False)
|
||||
@@ -3104,7 +3210,7 @@ class Edit(Modifier):
|
||||
if "Placement" in self.obj.PropertiesList:
|
||||
self.pl = self.obj.Placement
|
||||
self.invpl = self.pl.inverse()
|
||||
if Draft.getType(self.obj) in ["Wire","BSpline"]:
|
||||
if Draft.getType(self.obj) in ["Wire","BSpline","BezCurve"]:
|
||||
for p in self.obj.Points:
|
||||
if self.pl: p = self.pl.multVec(p)
|
||||
self.editpoints.append(p)
|
||||
@@ -3218,7 +3324,7 @@ class Edit(Modifier):
|
||||
self.numericInput(self.trackers[self.editing].get())
|
||||
|
||||
def update(self,v):
|
||||
if Draft.getType(self.obj) in ["Wire","BSpline"]:
|
||||
if Draft.getType(self.obj) in ["Wire","BSpline","BezCurve"]:
|
||||
pts = self.obj.Points
|
||||
editPnt = self.invpl.multVec(v)
|
||||
# DNC: allows to close the curve by placing ends close to each other
|
||||
@@ -3300,7 +3406,7 @@ class Edit(Modifier):
|
||||
self.node = []
|
||||
|
||||
def addPoint(self,point):
|
||||
if not (Draft.getType(self.obj) in ["Wire","BSpline"]): return
|
||||
if not (Draft.getType(self.obj) in ["Wire","BSpline","BezCurve"]): return
|
||||
pts = self.obj.Points
|
||||
if ( Draft.getType(self.obj) == "Wire" ):
|
||||
if (self.obj.Closed == True):
|
||||
@@ -3318,7 +3424,7 @@ class Edit(Modifier):
|
||||
else:
|
||||
# DNC: this version is much more reliable near sharp edges!
|
||||
curve = self.obj.Shape.Wires[0].approximate(0.0001,0.0001,100,25)
|
||||
elif ( Draft.getType(self.obj) == "BSpline" ):
|
||||
elif ( Draft.getType(self.obj) in ["BSpline","BezCurve"]):
|
||||
if (self.obj.Closed == True):
|
||||
curve = self.obj.Shape.Edges[0].Curve
|
||||
else:
|
||||
@@ -3340,7 +3446,7 @@ class Edit(Modifier):
|
||||
self.resetTrackers()
|
||||
|
||||
def delPoint(self,point):
|
||||
if not (Draft.getType(self.obj) in ["Wire","BSpline"]): return
|
||||
if not (Draft.getType(self.obj) in ["Wire","BSpline","BezCurve"]): return
|
||||
if len(self.obj.Points) <= 2:
|
||||
msg(translate("draft", "Active object must have more than two points/nodes\n"),'warning')
|
||||
else:
|
||||
@@ -4044,6 +4150,7 @@ FreeCADGui.addCommand('Draft_Rectangle',Rectangle())
|
||||
FreeCADGui.addCommand('Draft_Dimension',Dimension())
|
||||
FreeCADGui.addCommand('Draft_Polygon',Polygon())
|
||||
FreeCADGui.addCommand('Draft_BSpline',BSpline())
|
||||
FreeCADGui.addCommand('Draft_BezCurve',BezCurve())
|
||||
FreeCADGui.addCommand('Draft_Point',Point())
|
||||
FreeCADGui.addCommand('Draft_Ellipse',Ellipse())
|
||||
FreeCADGui.addCommand('Draft_ShapeString',ShapeString())
|
||||
|
||||
@@ -346,7 +346,77 @@ class bsplineTracker(Tracker):
|
||||
self.sep.addChild(self.bspline)
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning("bsplineTracker.recompute() failed to read-in Inventor string\n")
|
||||
|
||||
#######################################
|
||||
class bezcurveTracker(Tracker):
|
||||
"A bezcurve tracker"
|
||||
def __init__(self,dotted=False,scolor=None,swidth=None,points = []):
|
||||
self.bezcurve = None
|
||||
self.points = points
|
||||
self.trans = coin.SoTransform()
|
||||
self.sep = coin.SoSeparator()
|
||||
self.recompute()
|
||||
Tracker.__init__(self,dotted,scolor,swidth,[self.trans,self.sep])
|
||||
|
||||
def update(self, points):
|
||||
self.points = points
|
||||
self.recompute()
|
||||
|
||||
def recompute(self):
|
||||
if (len(self.points) >= 2):
|
||||
if self.bezcurve: self.sep.removeChild(self.bezcurve)
|
||||
self.bezcurve = None
|
||||
### c = Part.BSplineCurve() #!!!!!!!!!!!!!!!
|
||||
c = Part.BezierCurve()
|
||||
# DNC: allows to close the curve by placing ends close to each other
|
||||
if ( len(self.points) >= 3 ) and ( (self.points[0] - self.points[-1]).Length < Draft.tolerance() ):
|
||||
# YVH: Added a try to bypass some hazardous situations
|
||||
try:
|
||||
### c.interpolate(self.points[:-1], True) #!!!!!!!!!!!!
|
||||
c.setPoles(self.points[:-1])
|
||||
except:
|
||||
pass
|
||||
elif self.points:
|
||||
try:
|
||||
### c.interpolate(self.points, False) #!!!!!!!
|
||||
c.setPoles(self.points)
|
||||
except:
|
||||
pass
|
||||
c = c.toShape() #???? c = Part.Edge(c)?, c = Part.Wire(c)??
|
||||
buf=c.writeInventor(2,0.01)
|
||||
#fp=open("spline.iv","w")
|
||||
#fp.write(buf)
|
||||
#fp.close()
|
||||
try:
|
||||
ivin = coin.SoInput()
|
||||
ivin.setBuffer(buf)
|
||||
ivob = coin.SoDB.readAll(ivin)
|
||||
except:
|
||||
# workaround for pivy SoInput.setBuffer() bug
|
||||
import re
|
||||
buf = buf.replace("\n","")
|
||||
pts = re.findall("point \[(.*?)\]",buf)[0]
|
||||
pts = pts.split(",")
|
||||
pc = []
|
||||
for p in pts:
|
||||
v = p.strip().split()
|
||||
pc.append([float(v[0]),float(v[1]),float(v[2])])
|
||||
coords = coin.SoCoordinate3()
|
||||
coords.point.setValues(0,len(pc),pc)
|
||||
line = coin.SoLineSet()
|
||||
line.numVertices.setValue(-1)
|
||||
self.bezcurve = coin.SoSeparator()
|
||||
self.bezcurve.addChild(coords)
|
||||
self.bezcurve.addChild(line)
|
||||
self.sep.addChild(self.bezcurve)
|
||||
else:
|
||||
if ivob and ivob.getNumChildren() > 1:
|
||||
self.bezcurve = ivob.getChild(1).getChild(0)
|
||||
self.bezcurve.removeChild(self.bezcurve.getChild(0))
|
||||
self.bezcurve.removeChild(self.bezcurve.getChild(0))
|
||||
self.sep.addChild(self.bezcurve)
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning("bezcurveTracker.recompute() failed to read-in Inventor string\n")
|
||||
#######################################
|
||||
class arcTracker(Tracker):
|
||||
"An arc tracker"
|
||||
def __init__(self,dotted=False,scolor=None,swidth=None,start=0,end=math.pi*2,normal=None):
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -108,7 +108,7 @@ class DraftWorkbench (Workbench):
|
||||
self.cmdList = ["Draft_Line","Draft_Wire","Draft_Circle","Draft_Arc","Draft_Ellipse",
|
||||
"Draft_Polygon","Draft_Rectangle", "Draft_Text",
|
||||
"Draft_Dimension", "Draft_BSpline","Draft_Point",
|
||||
"Draft_ShapeString","Draft_Facebinder"]
|
||||
"Draft_ShapeString","Draft_Facebinder","Draft_BezCurve"]
|
||||
self.modList = ["Draft_Move","Draft_Rotate","Draft_Offset",
|
||||
"Draft_Trimex", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale",
|
||||
"Draft_Drawing","Draft_Edit","Draft_WireToBSpline","Draft_AddPoint",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<file>icons/Draft_Apply.svg</file>
|
||||
<file>icons/Draft_Arc.svg</file>
|
||||
<file>icons/Draft_BSpline.svg</file>
|
||||
<file>icons/Draft_BezCurve.svg</file>
|
||||
<file>icons/Draft_Circle.svg</file>
|
||||
<file>icons/Draft_Construction.svg</file>
|
||||
<file>icons/Draft_DelPoint.svg</file>
|
||||
|
||||
363
src/Mod/Draft/Resources/icons/Draft_BezCurve.svg
Normal file
363
src/Mod/Draft/Resources/icons/Draft_BezCurve.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 16 KiB |
Reference in New Issue
Block a user