Add Draft Bezier Curve draw & edit mockup using bSpline tools.

This commit is contained in:
WandererFan
2014-01-17 12:22:46 -05:00
committed by Yorik van Havre
parent 7eb7591a58
commit 2d43d61b92
8 changed files with 55349 additions and 16 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB