Skip to content

Commit

Permalink
Add Draft Bezier Curve draw & edit mockup using bSpline tools.
Browse files Browse the repository at this point in the history
  • Loading branch information
WandererFan authored and yorikvanhavre committed Feb 23, 2014
1 parent 7eb7591 commit 2d43d61
Show file tree
Hide file tree
Showing 8 changed files with 55,349 additions and 16 deletions.
73 changes: 72 additions & 1 deletion src/Mod/Draft/Draft.py
Expand Up @@ -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
Expand Down Expand Up @@ -3929,7 +3955,52 @@ def execute(self, obj):

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

Expand Down
2 changes: 1 addition & 1 deletion src/Mod/Draft/DraftGui.py
Expand Up @@ -1418,7 +1418,7 @@ def __init__(self):
"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())
Expand Down
119 changes: 113 additions & 6 deletions src/Mod/Draft/DraftTools.py
Expand Up @@ -665,7 +665,113 @@ def finish(self,closed=False,cont=False):
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"
Expand Down Expand Up @@ -3093,7 +3199,7 @@ def proceed(self):
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)
Expand All @@ -3104,7 +3210,7 @@ def proceed(self):
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)
Expand Down Expand Up @@ -3218,7 +3324,7 @@ def action(self,arg):
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
Expand Down Expand Up @@ -3300,7 +3406,7 @@ def numericInput(self,v,numy=None,numz=None):
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):
Expand All @@ -3318,7 +3424,7 @@ def addPoint(self,point):
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:
Expand All @@ -3340,7 +3446,7 @@ def addPoint(self,point):
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:
Expand Down Expand Up @@ -4044,6 +4150,7 @@ def Activated(self):
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())
Expand Down
72 changes: 71 additions & 1 deletion src/Mod/Draft/DraftTrackers.py
Expand Up @@ -346,7 +346,77 @@ def recompute(self):
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):
Expand Down

0 comments on commit 2d43d61

Please sign in to comment.