Draft: split wire related tools from Draft.py
Line Polyline BezCurve BSpline . . .
This commit is contained in:
committed by
Yorik van Havre
parent
76e97c7062
commit
1a04f97d8f
@@ -64,14 +64,20 @@ SET(Draft_functions
|
||||
|
||||
SET(Draft_make_functions
|
||||
draftmake/__init__.py
|
||||
draftmake/make_bezcurve.py
|
||||
draftmake/make_bspline.py
|
||||
draftmake/make_circle.py
|
||||
draftmake/make_line.py
|
||||
draftmake/make_polygon.py
|
||||
draftmake/make_rectangle.py
|
||||
draftmake/make_wire.py
|
||||
)
|
||||
|
||||
SET(Draft_objects
|
||||
draftobjects/__init__.py
|
||||
draftobjects/base.py
|
||||
draftobjects/bezcurve.py
|
||||
draftobjects/bspline.py
|
||||
draftobjects/circulararray.py
|
||||
draftobjects/circle.py
|
||||
draftobjects/orthoarray.py
|
||||
@@ -83,6 +89,7 @@ SET(Draft_objects
|
||||
draftobjects/polygon.py
|
||||
draftobjects/rectangle.py
|
||||
draftobjects/text.py
|
||||
draftobjects/wire.py
|
||||
draftobjects/README.md
|
||||
)
|
||||
|
||||
@@ -97,6 +104,7 @@ SET(Draft_view_providers
|
||||
draftviewproviders/view_dimension.py
|
||||
draftviewproviders/view_rectangle.py
|
||||
draftviewproviders/view_text.py
|
||||
draftviewproviders/view_wire.py
|
||||
draftviewproviders/README.md
|
||||
)
|
||||
|
||||
|
||||
@@ -206,7 +206,27 @@ if FreeCAD.GuiUp:
|
||||
from draftmake.make_polygon import make_polygon, makePolygon
|
||||
from draftobjects.polygon import Polygon, _Polygon
|
||||
|
||||
# wire and line
|
||||
from draftmake.make_line import make_line, makeLine
|
||||
from draftmake.make_wire import make_wire, makeWire
|
||||
from draftobjects.wire import Wire, _Wire
|
||||
if FreeCAD.GuiUp:
|
||||
from draftviewproviders.view_wire import ViewProviderWire
|
||||
from draftviewproviders.view_wire import _ViewProviderWire
|
||||
|
||||
# bspline
|
||||
from draftmake.make_bspline import make_bspline, makeBSpline
|
||||
from draftobjects.bspline import BSpline, _BSpline
|
||||
if FreeCAD.GuiUp:
|
||||
# for compatibility with older versions
|
||||
_ViewProviderBSpline = ViewProviderWire
|
||||
|
||||
# bezcurve
|
||||
from draftmake.make_bezcurve import make_bezcurve, makeBezCurve
|
||||
from draftobjects.bezcurve import BezCurve, _BezCurve
|
||||
if FreeCAD.GuiUp:
|
||||
# for compatibility with older versions
|
||||
_ViewProviderBezCurve = ViewProviderWire
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Draft annotation objects
|
||||
@@ -322,105 +342,6 @@ def makeWire(pointslist,closed=False,placement=None,face=None,support=None,bs2wi
|
||||
return obj
|
||||
|
||||
|
||||
def makeLine(p1,p2=None):
|
||||
"""makeLine(p1,p2): Creates a line between p1 and p2.
|
||||
makeLine(LineSegment): Creates a line from a Part.LineSegment
|
||||
makeLine(Shape): Creates a line from first vertex to last vertex of the given shape"""
|
||||
if not p2:
|
||||
if hasattr(p1,"StartPoint") and hasattr(p1,"EndPoint"):
|
||||
p2 = p1.EndPoint
|
||||
p1 = p1.StartPoint
|
||||
elif hasattr(p1,"Vertexes"):
|
||||
p2 = p1.Vertexes[-1].Point
|
||||
p1 = p1.Vertexes[0].Point
|
||||
else:
|
||||
FreeCAD.Console.PrintError("Unable to create a line from the given data\n")
|
||||
return
|
||||
obj = makeWire([p1,p2])
|
||||
return obj
|
||||
|
||||
def makeBSpline(pointslist,closed=False,placement=None,face=None,support=None):
|
||||
"""makeBSpline(pointslist,[closed],[placement]): Creates a B-Spline object
|
||||
from the given list of vectors. If closed is True or first
|
||||
and last points are identical, the wire is closed. If face is
|
||||
true (and wire is closed), the wire will appear filled. Instead of
|
||||
a pointslist, you can also pass a Part Wire."""
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
if not isinstance(pointslist,list):
|
||||
nlist = []
|
||||
for v in pointslist.Vertexes:
|
||||
nlist.append(v.Point)
|
||||
pointslist = nlist
|
||||
if len(pointslist) < 2:
|
||||
FreeCAD.Console.PrintError(translate("draft","Draft.makeBSpline: not enough points")+"\n")
|
||||
return
|
||||
if (pointslist[0] == pointslist[-1]):
|
||||
if len(pointslist) > 2:
|
||||
closed = True
|
||||
pointslist.pop()
|
||||
FreeCAD.Console.PrintWarning(translate("draft","Draft.makeBSpline: Equal endpoints forced Closed")+"\n")
|
||||
else: # len == 2 and first == last GIGO
|
||||
FreeCAD.Console.PrintError(translate("draft","Draft.makeBSpline: Invalid pointslist")+"\n")
|
||||
return
|
||||
# should have sensible parms from here on
|
||||
if placement: typecheck([(placement,FreeCAD.Placement)], "makeBSpline")
|
||||
if len(pointslist) == 2: fname = "Line"
|
||||
else: fname = "BSpline"
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",fname)
|
||||
_BSpline(obj)
|
||||
obj.Closed = closed
|
||||
obj.Points = pointslist
|
||||
obj.Support = support
|
||||
if face != None:
|
||||
obj.MakeFace = face
|
||||
if placement: obj.Placement = placement
|
||||
if gui:
|
||||
_ViewProviderWire(obj.ViewObject)
|
||||
formatObject(obj)
|
||||
select(obj)
|
||||
|
||||
return obj
|
||||
|
||||
def makeBezCurve(pointslist,closed=False,placement=None,face=None,support=None,degree=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 FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
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
|
||||
if degree:
|
||||
obj.Degree = degree
|
||||
else:
|
||||
import Part
|
||||
obj.Degree = min((len(pointslist)-(1 * (not closed))),
|
||||
Part.BezierCurve().MaxDegree)
|
||||
obj.Closed = closed
|
||||
obj.Support = support
|
||||
if face != None:
|
||||
obj.MakeFace = face
|
||||
obj.Proxy.resetcontinuity(obj)
|
||||
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)
|
||||
|
||||
return obj
|
||||
|
||||
def makeCopy(obj,force=None,reparent=False):
|
||||
"""makeCopy(object): returns an exact copy of an object"""
|
||||
if not FreeCAD.ActiveDocument:
|
||||
@@ -3102,270 +3023,6 @@ class _Ellipse(_DraftObject):
|
||||
obj.Placement = plm
|
||||
obj.positionBySupport()
|
||||
|
||||
class _Wire(_DraftObject):
|
||||
"""The Wire object"""
|
||||
|
||||
def __init__(self, obj):
|
||||
_DraftObject.__init__(self,obj,"Wire")
|
||||
obj.addProperty("App::PropertyVectorList","Points","Draft",QT_TRANSLATE_NOOP("App::Property","The vertices of the wire"))
|
||||
obj.addProperty("App::PropertyBool","Closed","Draft",QT_TRANSLATE_NOOP("App::Property","If the wire is closed or not"))
|
||||
obj.addProperty("App::PropertyLink","Base","Draft",QT_TRANSLATE_NOOP("App::Property","The base object is the wire, it's formed from 2 objects"))
|
||||
obj.addProperty("App::PropertyLink","Tool","Draft",QT_TRANSLATE_NOOP("App::Property","The tool object is the wire, it's formed from 2 objects"))
|
||||
obj.addProperty("App::PropertyVectorDistance","Start","Draft",QT_TRANSLATE_NOOP("App::Property","The start point of this line"))
|
||||
obj.addProperty("App::PropertyVectorDistance","End","Draft",QT_TRANSLATE_NOOP("App::Property","The end point of this line"))
|
||||
obj.addProperty("App::PropertyLength","Length","Draft",QT_TRANSLATE_NOOP("App::Property","The length of this line"))
|
||||
obj.addProperty("App::PropertyLength","FilletRadius","Draft",QT_TRANSLATE_NOOP("App::Property","Radius to use to fillet the corners"))
|
||||
obj.addProperty("App::PropertyLength","ChamferSize","Draft",QT_TRANSLATE_NOOP("App::Property","Size of the chamfer to give to the corners"))
|
||||
obj.addProperty("App::PropertyBool","MakeFace","Draft",QT_TRANSLATE_NOOP("App::Property","Create a face if this object is closed"))
|
||||
obj.addProperty("App::PropertyInteger","Subdivisions","Draft",QT_TRANSLATE_NOOP("App::Property","The number of subdivisions of each edge"))
|
||||
obj.addProperty("App::PropertyArea","Area","Draft",QT_TRANSLATE_NOOP("App::Property","The area of this object"))
|
||||
obj.MakeFace = getParam("fillmode",True)
|
||||
obj.Closed = False
|
||||
|
||||
def execute(self, obj):
|
||||
import Part, DraftGeomUtils
|
||||
plm = obj.Placement
|
||||
if obj.Base and (not obj.Tool):
|
||||
if obj.Base.isDerivedFrom("Sketcher::SketchObject"):
|
||||
shape = obj.Base.Shape.copy()
|
||||
if obj.Base.Shape.isClosed():
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
shape = Part.Face(shape)
|
||||
obj.Shape = shape
|
||||
elif obj.Base and obj.Tool:
|
||||
if hasattr(obj.Base,'Shape') and hasattr(obj.Tool,'Shape'):
|
||||
if (not obj.Base.Shape.isNull()) and (not obj.Tool.Shape.isNull()):
|
||||
sh1 = obj.Base.Shape.copy()
|
||||
sh2 = obj.Tool.Shape.copy()
|
||||
shape = sh1.fuse(sh2)
|
||||
if DraftGeomUtils.isCoplanar(shape.Faces):
|
||||
shape = DraftGeomUtils.concatenate(shape)
|
||||
obj.Shape = shape
|
||||
p = []
|
||||
for v in shape.Vertexes: p.append(v.Point)
|
||||
if obj.Points != p: obj.Points = p
|
||||
elif obj.Points:
|
||||
if obj.Points[0] == obj.Points[-1]:
|
||||
if not obj.Closed: obj.Closed = True
|
||||
obj.Points.pop()
|
||||
if obj.Closed and (len(obj.Points) > 2):
|
||||
pts = obj.Points
|
||||
if hasattr(obj,"Subdivisions"):
|
||||
if obj.Subdivisions > 0:
|
||||
npts = []
|
||||
for i in range(len(pts)):
|
||||
p1 = pts[i]
|
||||
npts.append(pts[i])
|
||||
if i == len(pts)-1:
|
||||
p2 = pts[0]
|
||||
else:
|
||||
p2 = pts[i+1]
|
||||
v = p2.sub(p1)
|
||||
v = DraftVecUtils.scaleTo(v,v.Length/(obj.Subdivisions+1))
|
||||
for j in range(obj.Subdivisions):
|
||||
npts.append(p1.add(FreeCAD.Vector(v).multiply(j+1)))
|
||||
pts = npts
|
||||
shape = Part.makePolygon(pts+[pts[0]])
|
||||
if "ChamferSize" in obj.PropertiesList:
|
||||
if obj.ChamferSize.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.ChamferSize.Value,chamfer=True)
|
||||
if w:
|
||||
shape = w
|
||||
if "FilletRadius" in obj.PropertiesList:
|
||||
if obj.FilletRadius.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.FilletRadius.Value)
|
||||
if w:
|
||||
shape = w
|
||||
try:
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
shape = Part.Face(shape)
|
||||
except Part.OCCError:
|
||||
pass
|
||||
else:
|
||||
edges = []
|
||||
pts = obj.Points[1:]
|
||||
lp = obj.Points[0]
|
||||
for p in pts:
|
||||
if not DraftVecUtils.equals(lp,p):
|
||||
if hasattr(obj,"Subdivisions"):
|
||||
if obj.Subdivisions > 0:
|
||||
npts = []
|
||||
v = p.sub(lp)
|
||||
v = DraftVecUtils.scaleTo(v,v.Length/(obj.Subdivisions+1))
|
||||
edges.append(Part.LineSegment(lp,lp.add(v)).toShape())
|
||||
lv = lp.add(v)
|
||||
for j in range(obj.Subdivisions):
|
||||
edges.append(Part.LineSegment(lv,lv.add(v)).toShape())
|
||||
lv = lv.add(v)
|
||||
else:
|
||||
edges.append(Part.LineSegment(lp,p).toShape())
|
||||
else:
|
||||
edges.append(Part.LineSegment(lp,p).toShape())
|
||||
lp = p
|
||||
try:
|
||||
shape = Part.Wire(edges)
|
||||
except Part.OCCError:
|
||||
print("Error wiring edges")
|
||||
shape = None
|
||||
if "ChamferSize" in obj.PropertiesList:
|
||||
if obj.ChamferSize.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.ChamferSize.Value,chamfer=True)
|
||||
if w:
|
||||
shape = w
|
||||
if "FilletRadius" in obj.PropertiesList:
|
||||
if obj.FilletRadius.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.FilletRadius.Value)
|
||||
if w:
|
||||
shape = w
|
||||
if shape:
|
||||
obj.Shape = shape
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
obj.Area = shape.Area
|
||||
if hasattr(obj,"Length"):
|
||||
obj.Length = shape.Length
|
||||
obj.Placement = plm
|
||||
obj.positionBySupport()
|
||||
self.onChanged(obj,"Placement")
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "Start":
|
||||
pts = obj.Points
|
||||
invpl = FreeCAD.Placement(obj.Placement).inverse()
|
||||
realfpstart = invpl.multVec(obj.Start)
|
||||
if pts:
|
||||
if pts[0] != realfpstart:
|
||||
pts[0] = realfpstart
|
||||
obj.Points = pts
|
||||
elif prop == "End":
|
||||
pts = obj.Points
|
||||
invpl = FreeCAD.Placement(obj.Placement).inverse()
|
||||
realfpend = invpl.multVec(obj.End)
|
||||
if len(pts) > 1:
|
||||
if pts[-1] != realfpend:
|
||||
pts[-1] = realfpend
|
||||
obj.Points = pts
|
||||
elif prop == "Length":
|
||||
if obj.Shape and not obj.Shape.isNull():
|
||||
if obj.Length.Value != obj.Shape.Length:
|
||||
if len(obj.Points) == 2:
|
||||
v = obj.Points[-1].sub(obj.Points[0])
|
||||
v = DraftVecUtils.scaleTo(v,obj.Length.Value)
|
||||
obj.Points = [obj.Points[0],obj.Points[0].add(v)]
|
||||
|
||||
elif prop == "Placement":
|
||||
pl = FreeCAD.Placement(obj.Placement)
|
||||
if len(obj.Points) >= 2:
|
||||
displayfpstart = pl.multVec(obj.Points[0])
|
||||
displayfpend = pl.multVec(obj.Points[-1])
|
||||
if obj.Start != displayfpstart:
|
||||
obj.Start = displayfpstart
|
||||
if obj.End != displayfpend:
|
||||
obj.End = displayfpend
|
||||
|
||||
|
||||
class _ViewProviderWire(_ViewProviderDraft):
|
||||
"""A View Provider for the Wire object"""
|
||||
def __init__(self, obj):
|
||||
_ViewProviderDraft.__init__(self,obj)
|
||||
obj.addProperty("App::PropertyBool","EndArrow","Draft",QT_TRANSLATE_NOOP("App::Property","Displays a Dimension symbol at the end of the wire"))
|
||||
obj.addProperty("App::PropertyLength","ArrowSize","Draft",QT_TRANSLATE_NOOP("App::Property","Arrow size"))
|
||||
obj.addProperty("App::PropertyEnumeration","ArrowType","Draft",QT_TRANSLATE_NOOP("App::Property","Arrow type"))
|
||||
obj.ArrowSize = getParam("arrowsize",0.1)
|
||||
obj.ArrowType = arrowtypes
|
||||
obj.ArrowType = arrowtypes[getParam("dimsymbol",0)]
|
||||
|
||||
def attach(self, obj):
|
||||
from pivy import coin
|
||||
self.Object = obj.Object
|
||||
col = coin.SoBaseColor()
|
||||
col.rgb.setValue(obj.LineColor[0],obj.LineColor[1],obj.LineColor[2])
|
||||
self.coords = coin.SoTransform()
|
||||
self.pt = coin.SoSeparator()
|
||||
self.pt.addChild(col)
|
||||
self.pt.addChild(self.coords)
|
||||
self.symbol = dimSymbol()
|
||||
self.pt.addChild(self.symbol)
|
||||
_ViewProviderDraft.attach(self,obj)
|
||||
self.onChanged(obj,"EndArrow")
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
from pivy import coin
|
||||
if prop == "Points":
|
||||
if obj.Points:
|
||||
p = obj.Points[-1]
|
||||
if hasattr(self,"coords"):
|
||||
self.coords.translation.setValue((p.x,p.y,p.z))
|
||||
if len(obj.Points) >= 2:
|
||||
v1 = obj.Points[-2].sub(obj.Points[-1])
|
||||
if not DraftVecUtils.isNull(v1):
|
||||
v1.normalize()
|
||||
_rot = coin.SbRotation()
|
||||
_rot.setValue(coin.SbVec3f(1, 0, 0), coin.SbVec3f(v1[0], v1[1], v1[2]))
|
||||
self.coords.rotation.setValue(_rot)
|
||||
return
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
from pivy import coin
|
||||
if prop in ["EndArrow","ArrowSize","ArrowType","Visibility"]:
|
||||
rn = vobj.RootNode
|
||||
if hasattr(self,"pt") and hasattr(vobj,"EndArrow"):
|
||||
if vobj.EndArrow and vobj.Visibility:
|
||||
self.pt.removeChild(self.symbol)
|
||||
s = arrowtypes.index(vobj.ArrowType)
|
||||
self.symbol = dimSymbol(s)
|
||||
self.pt.addChild(self.symbol)
|
||||
self.updateData(vobj.Object,"Points")
|
||||
if hasattr(vobj,"ArrowSize"):
|
||||
s = vobj.ArrowSize
|
||||
else:
|
||||
s = getParam("arrowsize",0.1)
|
||||
self.coords.scaleFactor.setValue((s,s,s))
|
||||
rn.addChild(self.pt)
|
||||
else:
|
||||
if self.symbol:
|
||||
if self.pt.findChild(self.symbol) != -1:
|
||||
self.pt.removeChild(self.symbol)
|
||||
if rn.findChild(self.pt) != -1:
|
||||
rn.removeChild(self.pt)
|
||||
if prop in ["LineColor"]:
|
||||
if hasattr(self, "pt"):
|
||||
self.pt[0].rgb.setValue(vobj.LineColor[0],vobj.LineColor[1],vobj.LineColor[2])
|
||||
_ViewProviderDraft.onChanged(self,vobj,prop)
|
||||
return
|
||||
|
||||
def claimChildren(self):
|
||||
if hasattr(self.Object,"Base"):
|
||||
return [self.Object.Base,self.Object.Tool]
|
||||
return []
|
||||
|
||||
def setupContextMenu(self,vobj,menu):
|
||||
from PySide import QtCore,QtGui
|
||||
action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Edit.svg"),"Flatten this wire",menu)
|
||||
QtCore.QObject.connect(action1,QtCore.SIGNAL("triggered()"),self.flatten)
|
||||
menu.addAction(action1)
|
||||
|
||||
def flatten(self):
|
||||
if hasattr(self,"Object"):
|
||||
if len(self.Object.Shape.Wires) == 1:
|
||||
import DraftGeomUtils
|
||||
fw = DraftGeomUtils.flattenWire(self.Object.Shape.Wires[0])
|
||||
points = [v.Point for v in fw.Vertexes]
|
||||
if len(points) == len(self.Object.Points):
|
||||
if points != self.Object.Points:
|
||||
FreeCAD.ActiveDocument.openTransaction("Flatten wire")
|
||||
FreeCADGui.doCommand("FreeCAD.ActiveDocument."+self.Object.Name+".Points="+str(points).replace("Vector","FreeCAD.Vector").replace(" ",""))
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
|
||||
else:
|
||||
from DraftTools import translate
|
||||
FreeCAD.Console.PrintMessage(translate("Draft","This Wire is already flat")+"\n")
|
||||
|
||||
|
||||
class _DrawingView(_DraftObject):
|
||||
"""The Draft DrawingView object"""
|
||||
@@ -3429,215 +3086,6 @@ class _DrawingView(_DraftObject):
|
||||
"returns a DXF fragment"
|
||||
return getDXF(obj)
|
||||
|
||||
class _BSpline(_DraftObject):
|
||||
"""The BSpline object"""
|
||||
|
||||
def __init__(self, obj):
|
||||
_DraftObject.__init__(self,obj,"BSpline")
|
||||
obj.addProperty("App::PropertyVectorList","Points","Draft", QT_TRANSLATE_NOOP("App::Property","The points of the B-spline"))
|
||||
obj.addProperty("App::PropertyBool","Closed","Draft",QT_TRANSLATE_NOOP("App::Property","If the B-spline is closed or not"))
|
||||
obj.addProperty("App::PropertyBool","MakeFace","Draft",QT_TRANSLATE_NOOP("App::Property","Create a face if this spline is closed"))
|
||||
obj.addProperty("App::PropertyArea","Area","Draft",QT_TRANSLATE_NOOP("App::Property","The area of this object"))
|
||||
obj.MakeFace = getParam("fillmode",True)
|
||||
obj.Closed = False
|
||||
obj.Points = []
|
||||
self.assureProperties(obj)
|
||||
|
||||
def assureProperties(self, obj): # for Compatibility with older versions
|
||||
if not hasattr(obj, "Parameterization"):
|
||||
obj.addProperty("App::PropertyFloat","Parameterization","Draft",QT_TRANSLATE_NOOP("App::Property","Parameterization factor"))
|
||||
obj.Parameterization = 1.0
|
||||
self.knotSeq = []
|
||||
|
||||
def parameterization (self, pts, a, closed):
|
||||
# Computes a knot Sequence for a set of points
|
||||
# fac (0-1) : parameterization factor
|
||||
# fac=0 -> Uniform / fac=0.5 -> Centripetal / fac=1.0 -> Chord-Length
|
||||
if closed: # we need to add the first point as the end point
|
||||
pts.append(pts[0])
|
||||
params = [0]
|
||||
for i in range(1,len(pts)):
|
||||
p = pts[i].sub(pts[i-1])
|
||||
pl = pow(p.Length,a)
|
||||
params.append(params[-1] + pl)
|
||||
return params
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
if prop == "Parameterization":
|
||||
if fp.Parameterization < 0.:
|
||||
fp.Parameterization = 0.
|
||||
if fp.Parameterization > 1.0:
|
||||
fp.Parameterization = 1.0
|
||||
|
||||
def execute(self, obj):
|
||||
import Part
|
||||
self.assureProperties(obj)
|
||||
if obj.Points:
|
||||
self.knotSeq = self.parameterization(obj.Points, obj.Parameterization, obj.Closed)
|
||||
plm = obj.Placement
|
||||
if obj.Closed and (len(obj.Points) > 2):
|
||||
if obj.Points[0] == obj.Points[-1]: # should not occur, but OCC will crash
|
||||
FreeCAD.Console.PrintError(translate('draft', "_BSpline.createGeometry: Closed with same first/last Point. Geometry not updated.")+"\n")
|
||||
return
|
||||
spline = Part.BSplineCurve()
|
||||
spline.interpolate(obj.Points, PeriodicFlag = True, Parameters = self.knotSeq)
|
||||
# DNC: bug fix: convert to face if closed
|
||||
shape = Part.Wire(spline.toShape())
|
||||
# Creating a face from a closed spline cannot be expected to always work
|
||||
# Usually, if the spline is not flat the call of Part.Face() fails
|
||||
try:
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
shape = Part.Face(shape)
|
||||
except Part.OCCError:
|
||||
pass
|
||||
obj.Shape = shape
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
obj.Area = shape.Area
|
||||
else:
|
||||
spline = Part.BSplineCurve()
|
||||
spline.interpolate(obj.Points, PeriodicFlag = False, Parameters = self.knotSeq)
|
||||
shape = spline.toShape()
|
||||
obj.Shape = shape
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
obj.Area = shape.Area
|
||||
obj.Placement = plm
|
||||
obj.positionBySupport()
|
||||
|
||||
# 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",QT_TRANSLATE_NOOP("App::Property","The points of the Bezier curve"))
|
||||
obj.addProperty("App::PropertyInteger","Degree","Draft",QT_TRANSLATE_NOOP("App::Property","The degree of the Bezier function"))
|
||||
obj.addProperty("App::PropertyIntegerList","Continuity","Draft",QT_TRANSLATE_NOOP("App::Property","Continuity"))
|
||||
obj.addProperty("App::PropertyBool","Closed","Draft",QT_TRANSLATE_NOOP("App::Property","If the Bezier curve should be closed or not"))
|
||||
obj.addProperty("App::PropertyBool","MakeFace","Draft",QT_TRANSLATE_NOOP("App::Property","Create a face if this curve is closed"))
|
||||
obj.addProperty("App::PropertyLength","Length","Draft",QT_TRANSLATE_NOOP("App::Property","The length of this object"))
|
||||
obj.addProperty("App::PropertyArea","Area","Draft",QT_TRANSLATE_NOOP("App::Property","The area of this object"))
|
||||
obj.MakeFace = getParam("fillmode",True)
|
||||
obj.Closed = False
|
||||
obj.Degree = 3
|
||||
obj.Continuity = []
|
||||
#obj.setEditorMode("Degree",2)#hide
|
||||
obj.setEditorMode("Continuity",1)#ro
|
||||
|
||||
def execute(self, fp):
|
||||
self.createGeometry(fp)
|
||||
fp.positionBySupport()
|
||||
|
||||
def _segpoleslst(self,fp):
|
||||
"""split the points into segments"""
|
||||
if not fp.Closed and len(fp.Points) >= 2: #allow lower degree segment
|
||||
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 \
|
||||
range(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):
|
||||
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)
|
||||
|
||||
def createGeometry(self,fp):
|
||||
import Part
|
||||
plm = fp.Placement
|
||||
if fp.Points:
|
||||
startpoint=fp.Points[0]
|
||||
edges = []
|
||||
for segpoles in self._segpoleslst(fp):
|
||||
# if len(segpoles) == fp.Degree # would skip additional poles
|
||||
c = Part.BezierCurve() #last segment may have lower degree
|
||||
c.increase(len(segpoles))
|
||||
c.setPoles([startpoint]+segpoles)
|
||||
edges.append(Part.Edge(c))
|
||||
startpoint = segpoles[-1]
|
||||
w = Part.Wire(edges)
|
||||
if fp.Closed and w.isClosed():
|
||||
try:
|
||||
if hasattr(fp,"MakeFace"):
|
||||
if fp.MakeFace:
|
||||
w = Part.Face(w)
|
||||
else:
|
||||
w = Part.Face(w)
|
||||
except Part.OCCError:
|
||||
pass
|
||||
fp.Shape = w
|
||||
if hasattr(fp,"Area") and hasattr(w,"Area"):
|
||||
fp.Area = w.Area
|
||||
if hasattr(fp,"Length") and hasattr(w,"Length"):
|
||||
fp.Length = w.Length
|
||||
fp.Placement = plm
|
||||
|
||||
@classmethod
|
||||
def symmetricpoles(cls,knot, p1, p2):
|
||||
"""make two poles symmetric respective to the knot"""
|
||||
p1h=FreeCAD.Vector(p1)
|
||||
p2h=FreeCAD.Vector(p2)
|
||||
p1h.multiply(0.5)
|
||||
p2h.multiply(0.5)
|
||||
return ( knot+p1h-p2h , knot+p2h-p1h)
|
||||
|
||||
@classmethod
|
||||
def tangentpoles(cls,knot, p1, p2,allowsameside=False):
|
||||
"""make two poles have the same tangent at knot"""
|
||||
p12n=p2.sub(p1)
|
||||
p12n.normalize()
|
||||
p1k=knot-p1
|
||||
p2k=knot-p2
|
||||
p1k_= FreeCAD.Vector(p12n)
|
||||
kon12=(p1k*p12n)
|
||||
if allowsameside or not (kon12 < 0 or p2k*p12n > 0):# instead of moving
|
||||
p1k_.multiply(kon12)
|
||||
pk_k=knot-p1-p1k_
|
||||
return (p1+pk_k,p2+pk_k)
|
||||
else:
|
||||
return cls.symmetricpoles(knot, p1, p2)
|
||||
|
||||
@staticmethod
|
||||
def modifysymmetricpole(knot,p1):
|
||||
"""calculate the coordinates of the opposite pole
|
||||
of a symmetric knot"""
|
||||
return knot+knot-p1
|
||||
|
||||
@staticmethod
|
||||
def modifytangentpole(knot,p1,oldp2):
|
||||
"""calculate the coordinates of the opposite pole
|
||||
of a tangent knot"""
|
||||
pn=knot-p1
|
||||
pn.normalize()
|
||||
pn.multiply((knot-oldp2).Length)
|
||||
return pn+knot
|
||||
|
||||
# for compatibility with older versions ???????
|
||||
_ViewProviderBezCurve = _ViewProviderWire
|
||||
|
||||
class _Block(_DraftObject):
|
||||
"""The Block object"""
|
||||
|
||||
107
src/Mod/Draft/draftmake/make_bezcurve.py
Normal file
107
src/Mod/Draft/draftmake/make_bezcurve.py
Normal file
@@ -0,0 +1,107 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * Copyright (c) 2020 FreeCAD Developers *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the code for Draft make_bezcurve function.
|
||||
"""
|
||||
## @package make_bezcurve
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the code for Draft make_bezcurve function.
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
from draftutils.gui_utils import format_object
|
||||
from draftutils.gui_utils import select
|
||||
|
||||
from draftutils.utils import type_check
|
||||
from draftutils.translate import translate
|
||||
|
||||
from draftobjects.bezcurve import BezCurve
|
||||
if App.GuiUp:
|
||||
from draftviewproviders.view_bezcurve import ViewProviderBezCurve
|
||||
|
||||
|
||||
def make_bezcurve(pointslist, closed=False, placement=None, face=None, support=None, degree=None):
|
||||
"""make_bezcurve(pointslist, [closed], [placement])
|
||||
|
||||
Creates a Bezier Curve object from the given list of vectors.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pointlist : [Base.Vector]
|
||||
List of points to create the polyline.
|
||||
Instead of a pointslist, you can also pass a Part Wire.
|
||||
TODO: Change the name so!
|
||||
|
||||
closed : bool
|
||||
If closed is True or first and last points are identical,
|
||||
the created BSpline will be closed.
|
||||
|
||||
placement : Base.Placement
|
||||
If a placement is given, it is used.
|
||||
|
||||
face : Bool
|
||||
If face is False, the rectangle is shown as a wireframe,
|
||||
otherwise as a face.
|
||||
|
||||
support :
|
||||
TODO: Describe
|
||||
|
||||
degree : int
|
||||
Degree of the BezCurve
|
||||
"""
|
||||
if not App.ActiveDocument:
|
||||
App.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
if not isinstance(pointslist,list):
|
||||
nlist = []
|
||||
for v in pointslist.Vertexes:
|
||||
nlist.append(v.Point)
|
||||
pointslist = nlist
|
||||
if placement: type_check([(placement,App.Placement)], "make_bezcurve")
|
||||
if len(pointslist) == 2: fname = "Line"
|
||||
else: fname = "BezCurve"
|
||||
obj = App.ActiveDocument.addObject("Part::Part2DObjectPython",fname)
|
||||
BezCurve(obj)
|
||||
obj.Points = pointslist
|
||||
if degree:
|
||||
obj.Degree = degree
|
||||
else:
|
||||
import Part
|
||||
obj.Degree = min((len(pointslist)-(1 * (not closed))),
|
||||
Part.BezierCurve().MaxDegree)
|
||||
obj.Closed = closed
|
||||
obj.Support = support
|
||||
if face != None:
|
||||
obj.MakeFace = face
|
||||
obj.Proxy.resetcontinuity(obj)
|
||||
if placement: obj.Placement = placement
|
||||
if App.GuiUp:
|
||||
ViewProviderBezCurve(obj.ViewObject)
|
||||
# if not face: obj.ViewObject.DisplayMode = "Wireframe"
|
||||
# obj.ViewObject.DisplayMode = "Wireframe"
|
||||
format_object(obj)
|
||||
select(obj)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
makeBezCurve = make_bezcurve
|
||||
111
src/Mod/Draft/draftmake/make_bspline.py
Normal file
111
src/Mod/Draft/draftmake/make_bspline.py
Normal file
@@ -0,0 +1,111 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * Copyright (c) 2020 FreeCAD Developers *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the code for Draft make_bspline function.
|
||||
"""
|
||||
## @package make_bspline
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the code for Draft make_bspline function.
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
from draftutils.gui_utils import format_object
|
||||
from draftutils.gui_utils import select
|
||||
|
||||
from draftutils.utils import type_check
|
||||
from draftutils.translate import translate
|
||||
|
||||
from draftobjects.bspline import BSpline
|
||||
if App.GuiUp:
|
||||
from draftviewproviders.view_bspline import ViewProviderBSpline
|
||||
|
||||
|
||||
def make_bspline(pointslist, closed=False, placement=None, face=None, support=None):
|
||||
"""make_bspline(pointslist, [closed], [placement])
|
||||
|
||||
Creates a B-Spline object from the given list of vectors.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pointlist : [Base.Vector]
|
||||
List of points to create the polyline.
|
||||
Instead of a pointslist, you can also pass a Part Wire.
|
||||
TODO: Change the name so!
|
||||
|
||||
closed : bool
|
||||
If closed is True or first and last points are identical,
|
||||
the created BSpline will be closed.
|
||||
|
||||
placement : Base.Placement
|
||||
If a placement is given, it is used.
|
||||
|
||||
face : Bool
|
||||
If face is False, the rectangle is shown as a wireframe,
|
||||
otherwise as a face.
|
||||
|
||||
support :
|
||||
TODO: Describe
|
||||
"""
|
||||
if not App.ActiveDocument:
|
||||
App.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
if not isinstance(pointslist,list):
|
||||
nlist = []
|
||||
for v in pointslist.Vertexes:
|
||||
nlist.append(v.Point)
|
||||
pointslist = nlist
|
||||
if len(pointslist) < 2:
|
||||
_err = "Draft.makeBSpline: not enough points"
|
||||
App.Console.PrintError(translate("draft", _err)+"\n")
|
||||
return
|
||||
if (pointslist[0] == pointslist[-1]):
|
||||
if len(pointslist) > 2:
|
||||
closed = True
|
||||
pointslist.pop()
|
||||
_err = "Draft.makeBSpline: Equal endpoints forced Closed"
|
||||
App.Console.PrintWarning(translate("Draft", _err) + _err + "\n")
|
||||
else:
|
||||
# len == 2 and first == last GIGO
|
||||
_err = "Draft.makeBSpline: Invalid pointslist"
|
||||
App.Console.PrintError(translate("Draft", _err)+"\n")
|
||||
return
|
||||
# should have sensible parms from here on
|
||||
if placement: type_check([(placement,App.Placement)], "make_bspline")
|
||||
if len(pointslist) == 2: fname = "Line"
|
||||
else: fname = "BSpline"
|
||||
obj = App.ActiveDocument.addObject("Part::Part2DObjectPython",fname)
|
||||
BSpline(obj)
|
||||
obj.Closed = closed
|
||||
obj.Points = pointslist
|
||||
obj.Support = support
|
||||
if face != None:
|
||||
obj.MakeFace = face
|
||||
if placement: obj.Placement = placement
|
||||
if App.GuiUp:
|
||||
ViewProviderBSpline(obj.ViewObject)
|
||||
format_object(obj)
|
||||
select(obj)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
makeBSpline = make_bspline
|
||||
73
src/Mod/Draft/draftmake/make_line.py
Normal file
73
src/Mod/Draft/draftmake/make_line.py
Normal file
@@ -0,0 +1,73 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * Copyright (c) 2020 FreeCAD Developers *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the code for Draft make_line function.
|
||||
"""
|
||||
## @package make_line
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the code for Draft make_line function.
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
from draftutils.gui_utils import format_object
|
||||
from draftutils.gui_utils import select
|
||||
|
||||
from draftmake.make_wire import make_wire
|
||||
|
||||
|
||||
def make_line(first_param, last_param=None):
|
||||
"""makeLine(first_param, p2)
|
||||
|
||||
Creates a line from 2 points or from a given object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
first_param :
|
||||
Base.Vector -> First point of the line (if p2 == None)
|
||||
Part.LineSegment -> Line is created from the given Linesegment
|
||||
Shape -> Line is created from the give Shape
|
||||
|
||||
last_param : Base.Vector
|
||||
Second point of the line, if not set the function evaluates
|
||||
the first_param to look for a Part.LineSegment or a Shape
|
||||
"""
|
||||
if last_param:
|
||||
p1 = first_param
|
||||
p2 = last_param
|
||||
else:
|
||||
if hasattr(first_param, "StartPoint") and hasattr(first_param, "EndPoint"):
|
||||
p2 = first_param.EndPoint
|
||||
p1 = first_param.StartPoint
|
||||
elif hasattr(p1,"Vertexes"):
|
||||
p2 = first_param.Vertexes[-1].Point
|
||||
p1 = first_param.Vertexes[0].Point
|
||||
else:
|
||||
_err = "Unable to create a line from the given parameters"
|
||||
App.Console.PrintError(_err + "\n")
|
||||
return
|
||||
|
||||
obj = make_wire([p1,p2])
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
makeLine = make_line
|
||||
123
src/Mod/Draft/draftmake/make_wire.py
Normal file
123
src/Mod/Draft/draftmake/make_wire.py
Normal file
@@ -0,0 +1,123 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the code for Draft make_wire function.
|
||||
"""
|
||||
## @package make_wire
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the code for Draft make_wire function.
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
import DraftGeomUtils
|
||||
|
||||
from draftutils.gui_utils import format_object
|
||||
from draftutils.gui_utils import select
|
||||
|
||||
from draftutils.utils import type_check
|
||||
|
||||
from draftobjects.wire import Wire
|
||||
if App.GuiUp:
|
||||
from draftviewproviders.view_wire import ViewProviderWire
|
||||
|
||||
|
||||
def make_wire(pointslist, closed=False, placement=None, face=None, support=None, bs2wire=False):
|
||||
"""makeWire(pointslist,[closed],[placement])
|
||||
|
||||
Creates a Wire object from the given list of vectors. If face is
|
||||
true (and wire is closed), the wire will appear filled. Instead of
|
||||
a pointslist, you can also pass a Part Wire.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pointlist : [Base.Vector]
|
||||
List of points to create the polyline
|
||||
|
||||
closed : bool
|
||||
If closed is True or first and last points are identical,
|
||||
the created polyline will be closed.
|
||||
|
||||
placement : Base.Placement
|
||||
If a placement is given, it is used.
|
||||
|
||||
face : Bool
|
||||
If face is False, the rectangle is shown as a wireframe,
|
||||
otherwise as a face.
|
||||
|
||||
support :
|
||||
TODO: Describe
|
||||
|
||||
bs2wire : bool
|
||||
TODO: Describe
|
||||
"""
|
||||
if not App.ActiveDocument:
|
||||
App.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
|
||||
import Part
|
||||
|
||||
if not isinstance(pointslist, list):
|
||||
e = pointslist.Wires[0].Edges
|
||||
pointslist = Part.Wire(Part.__sortEdges__(e))
|
||||
nlist = []
|
||||
for v in pointslist.Vertexes:
|
||||
nlist.append(v.Point)
|
||||
if DraftGeomUtils.isReallyClosed(pointslist):
|
||||
closed = True
|
||||
pointslist = nlist
|
||||
|
||||
if len(pointslist) == 0:
|
||||
print("Invalid input points: ", pointslist)
|
||||
#print(pointslist)
|
||||
#print(closed)
|
||||
|
||||
if placement:
|
||||
type_check([(placement, App.Placement)], "make_wire")
|
||||
ipl = placement.inverse()
|
||||
if not bs2wire:
|
||||
pointslist = [ipl.multVec(p) for p in pointslist]
|
||||
|
||||
if len(pointslist) == 2:
|
||||
fname = "Line"
|
||||
else:
|
||||
fname = "Wire"
|
||||
|
||||
obj = App.ActiveDocument.addObject("Part::Part2DObjectPython", fname)
|
||||
Wire(obj)
|
||||
obj.Points = pointslist
|
||||
obj.Closed = closed
|
||||
obj.Support = support
|
||||
|
||||
if face != None:
|
||||
obj.MakeFace = face
|
||||
|
||||
if placement:
|
||||
obj.Placement = placement
|
||||
|
||||
if App.GuiUp:
|
||||
ViewProviderWire(obj.ViewObject)
|
||||
format_object(obj)
|
||||
select(obj)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
makeWire = make_wire
|
||||
196
src/Mod/Draft/draftobjects/bezcurve.py
Normal file
196
src/Mod/Draft/draftobjects/bezcurve.py
Normal file
@@ -0,0 +1,196 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * Copyright (c) 2020 FreeCAD Developers *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the object code for Draft BezCurve.
|
||||
"""
|
||||
## @package bezcurve
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the object code for Draft BezCurve.
|
||||
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
from draftutils.utils import get_param
|
||||
|
||||
from draftobjects.base import DraftObject
|
||||
|
||||
|
||||
class BezCurve(DraftObject):
|
||||
"""The BezCurve object"""
|
||||
|
||||
def __init__(self, obj):
|
||||
super(BezCurve, self).__init__(obj, "BezCurve")
|
||||
|
||||
_tip = "The points of the Bezier curve"
|
||||
obj.addProperty("App::PropertyVectorList", "Points",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The degree of the Bezier function"
|
||||
obj.addProperty("App::PropertyInteger", "Degree",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "Continuity"
|
||||
obj.addProperty("App::PropertyIntegerList", "Continuity",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "If the Bezier curve should be closed or not"
|
||||
obj.addProperty("App::PropertyBool", "Closed",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "Create a face if this curve is closed"
|
||||
obj.addProperty("App::PropertyBool", "MakeFace",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The length of this object"
|
||||
obj.addProperty("App::PropertyLength", "Length",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The area of this object"
|
||||
obj.addProperty("App::PropertyArea", "Area",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
obj.MakeFace = get_param("fillmode", True)
|
||||
obj.Closed = False
|
||||
obj.Degree = 3
|
||||
obj.Continuity = []
|
||||
#obj.setEditorMode("Degree",2)
|
||||
obj.setEditorMode("Continuity", 1)
|
||||
|
||||
def execute(self, fp):
|
||||
self.createGeometry(fp)
|
||||
fp.positionBySupport()
|
||||
|
||||
def _segpoleslst(self,fp):
|
||||
"""Split the points into segments."""
|
||||
if not fp.Closed and len(fp.Points) >= 2: #allow lower degree segment
|
||||
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 \
|
||||
range(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):
|
||||
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:
|
||||
self.resetcontinuity(fp)
|
||||
|
||||
if prop in ["Points","Degree","Continuity","Closed"]:
|
||||
self.createGeometry(fp)
|
||||
|
||||
def createGeometry(self,fp):
|
||||
import Part
|
||||
plm = fp.Placement
|
||||
if fp.Points:
|
||||
startpoint=fp.Points[0]
|
||||
edges = []
|
||||
for segpoles in self._segpoleslst(fp):
|
||||
# if len(segpoles) == fp.Degree # would skip additional poles
|
||||
c = Part.BezierCurve() #last segment may have lower degree
|
||||
c.increase(len(segpoles))
|
||||
c.setPoles([startpoint]+segpoles)
|
||||
edges.append(Part.Edge(c))
|
||||
startpoint = segpoles[-1]
|
||||
w = Part.Wire(edges)
|
||||
if fp.Closed and w.isClosed():
|
||||
try:
|
||||
if hasattr(fp,"MakeFace"):
|
||||
if fp.MakeFace:
|
||||
w = Part.Face(w)
|
||||
else:
|
||||
w = Part.Face(w)
|
||||
except Part.OCCError:
|
||||
pass
|
||||
fp.Shape = w
|
||||
if hasattr(fp,"Area") and hasattr(w,"Area"):
|
||||
fp.Area = w.Area
|
||||
if hasattr(fp,"Length") and hasattr(w,"Length"):
|
||||
fp.Length = w.Length
|
||||
fp.Placement = plm
|
||||
|
||||
@classmethod
|
||||
def symmetricpoles(cls,knot, p1, p2):
|
||||
"""Make two poles symmetric respective to the knot."""
|
||||
p1h = App.Vector(p1)
|
||||
p2h = App.Vector(p2)
|
||||
p1h.multiply(0.5)
|
||||
p2h.multiply(0.5)
|
||||
return ( knot+p1h-p2h , knot+p2h-p1h )
|
||||
|
||||
@classmethod
|
||||
def tangentpoles(cls,knot, p1, p2,allowsameside=False):
|
||||
"""Make two poles have the same tangent at knot."""
|
||||
p12n = p2.sub(p1)
|
||||
p12n.normalize()
|
||||
p1k = knot-p1
|
||||
p2k = knot-p2
|
||||
p1k_= App.Vector(p12n)
|
||||
kon12=(p1k * p12n)
|
||||
if allowsameside or not (kon12 < 0 or p2k * p12n > 0):# instead of moving
|
||||
p1k_.multiply(kon12)
|
||||
pk_k = knot - p1 - p1k_
|
||||
return (p1 + pk_k, p2 + pk_k)
|
||||
else:
|
||||
return cls.symmetricpoles(knot, p1, p2)
|
||||
|
||||
@staticmethod
|
||||
def modifysymmetricpole(knot,p1):
|
||||
"""calculate the coordinates of the opposite pole
|
||||
of a symmetric knot"""
|
||||
return knot + knot - p1
|
||||
|
||||
@staticmethod
|
||||
def modifytangentpole(knot,p1,oldp2):
|
||||
"""calculate the coordinates of the opposite pole
|
||||
of a tangent knot"""
|
||||
pn = knot - p1
|
||||
pn.normalize()
|
||||
pn.multiply((knot - oldp2).Length)
|
||||
return pn + knot
|
||||
|
||||
|
||||
_BezCurve = BezCurve
|
||||
136
src/Mod/Draft/draftobjects/bspline.py
Normal file
136
src/Mod/Draft/draftobjects/bspline.py
Normal file
@@ -0,0 +1,136 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * Copyright (c) 2020 FreeCAD Developers *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the object code for Draft BSpline.
|
||||
"""
|
||||
## @package bspline
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the object code for Draft BSpline.
|
||||
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
from draftutils.utils import get_param
|
||||
|
||||
from draftobjects.base import DraftObject
|
||||
|
||||
|
||||
class BSpline(DraftObject):
|
||||
"""The BSpline object"""
|
||||
|
||||
def __init__(self, obj):
|
||||
super(BSpline, self).__init__(obj, "BSpline")
|
||||
|
||||
_tip = "The points of the B-spline"
|
||||
obj.addProperty("App::PropertyVectorList","Points",
|
||||
"Draft", QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "If the B-spline is closed or not"
|
||||
obj.addProperty("App::PropertyBool","Closed",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "Create a face if this spline is closed"
|
||||
obj.addProperty("App::PropertyBool","MakeFace",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The area of this object"
|
||||
obj.addProperty("App::PropertyArea","Area",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
obj.MakeFace = get_param("fillmode",True)
|
||||
obj.Closed = False
|
||||
obj.Points = []
|
||||
self.assureProperties(obj)
|
||||
|
||||
def assureProperties(self, obj): # for Compatibility with older versions
|
||||
if not hasattr(obj, "Parameterization"):
|
||||
obj.addProperty("App::PropertyFloat","Parameterization","Draft",QT_TRANSLATE_NOOP("App::Property","Parameterization factor"))
|
||||
obj.Parameterization = 1.0
|
||||
self.knotSeq = []
|
||||
|
||||
def parameterization (self, pts, a, closed):
|
||||
"""Computes a knot Sequence for a set of points.
|
||||
fac (0-1) : parameterization factor
|
||||
fac = 0 -> Uniform / fac=0.5 -> Centripetal / fac=1.0 -> Chord-Length
|
||||
"""
|
||||
if closed: # we need to add the first point as the end point
|
||||
pts.append(pts[0])
|
||||
params = [0]
|
||||
for i in range(1,len(pts)):
|
||||
p = pts[i].sub(pts[i-1])
|
||||
pl = pow(p.Length,a)
|
||||
params.append(params[-1] + pl)
|
||||
return params
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
if prop == "Parameterization":
|
||||
if fp.Parameterization < 0.:
|
||||
fp.Parameterization = 0.
|
||||
if fp.Parameterization > 1.0:
|
||||
fp.Parameterization = 1.0
|
||||
|
||||
def execute(self, obj):
|
||||
import Part
|
||||
|
||||
self.assureProperties(obj)
|
||||
|
||||
if not obj.Points:
|
||||
obj.positionBySupport()
|
||||
|
||||
self.knotSeq = self.parameterization(obj.Points, obj.Parameterization, obj.Closed)
|
||||
plm = obj.Placement
|
||||
if obj.Closed and (len(obj.Points) > 2):
|
||||
if obj.Points[0] == obj.Points[-1]: # should not occur, but OCC will crash
|
||||
_err = "_BSpline.createGeometry: \
|
||||
Closed with same first/last Point. Geometry not updated."
|
||||
App.Console.PrintError(QT_TRANSLATE_NOOP('Draft', _err)+"\n")
|
||||
return
|
||||
spline = Part.BSplineCurve()
|
||||
spline.interpolate(obj.Points, PeriodicFlag = True, Parameters = self.knotSeq)
|
||||
# DNC: bug fix: convert to face if closed
|
||||
shape = Part.Wire(spline.toShape())
|
||||
# Creating a face from a closed spline cannot be expected to always work
|
||||
# Usually, if the spline is not flat the call of Part.Face() fails
|
||||
try:
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
shape = Part.Face(shape)
|
||||
except Part.OCCError:
|
||||
pass
|
||||
obj.Shape = shape
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
obj.Area = shape.Area
|
||||
else:
|
||||
spline = Part.BSplineCurve()
|
||||
spline.interpolate(obj.Points, PeriodicFlag = False, Parameters = self.knotSeq)
|
||||
shape = spline.toShape()
|
||||
obj.Shape = shape
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
obj.Area = shape.Area
|
||||
obj.Placement = plm
|
||||
obj.positionBySupport()
|
||||
|
||||
|
||||
_BSpline = BSpline
|
||||
251
src/Mod/Draft/draftobjects/wire.py
Normal file
251
src/Mod/Draft/draftobjects/wire.py
Normal file
@@ -0,0 +1,251 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * Copyright (c) 2020 FreeCAD Developers *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the object code for Draft Wire.
|
||||
"""
|
||||
## @package wire
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the object code for Draft Wire.
|
||||
|
||||
import math
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
import DraftGeomUtils
|
||||
import DraftVecUtils
|
||||
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
from draftutils.utils import get_param
|
||||
|
||||
from draftobjects.base import DraftObject
|
||||
|
||||
|
||||
|
||||
class Wire(DraftObject):
|
||||
"""The Wire object"""
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Wire, self).__init__(obj, "Wire")
|
||||
|
||||
_tip = "The vertices of the wire"
|
||||
obj.addProperty("App::PropertyVectorList","Points",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "If the wire is closed or not"
|
||||
obj.addProperty("App::PropertyBool","Closed",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The base object is the wire, it's formed from 2 objects"
|
||||
obj.addProperty("App::PropertyLink","Base",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The tool object is the wire, it's formed from 2 objects"
|
||||
obj.addProperty("App::PropertyLink","Tool",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The start point of this line"
|
||||
obj.addProperty("App::PropertyVectorDistance","Start",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The end point of this line"
|
||||
obj.addProperty("App::PropertyVectorDistance","End",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The length of this line"
|
||||
obj.addProperty("App::PropertyLength","Length",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "Radius to use to fillet the corners"
|
||||
obj.addProperty("App::PropertyLength","FilletRadius",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "Size of the chamfer to give to the corners"
|
||||
obj.addProperty("App::PropertyLength","ChamferSize",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "Create a face if this object is closed"
|
||||
obj.addProperty("App::PropertyBool","MakeFace",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The number of subdivisions of each edge"
|
||||
obj.addProperty("App::PropertyInteger","Subdivisions",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "The area of this object"
|
||||
obj.addProperty("App::PropertyArea","Area",
|
||||
"Draft",QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
obj.MakeFace = get_param("fillmode",True)
|
||||
obj.Closed = False
|
||||
|
||||
def execute(self, obj):
|
||||
import Part
|
||||
plm = obj.Placement
|
||||
if obj.Base and (not obj.Tool):
|
||||
if obj.Base.isDerivedFrom("Sketcher::SketchObject"):
|
||||
shape = obj.Base.Shape.copy()
|
||||
if obj.Base.Shape.isClosed():
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
shape = Part.Face(shape)
|
||||
obj.Shape = shape
|
||||
elif obj.Base and obj.Tool:
|
||||
if hasattr(obj.Base,'Shape') and hasattr(obj.Tool,'Shape'):
|
||||
if (not obj.Base.Shape.isNull()) and (not obj.Tool.Shape.isNull()):
|
||||
sh1 = obj.Base.Shape.copy()
|
||||
sh2 = obj.Tool.Shape.copy()
|
||||
shape = sh1.fuse(sh2)
|
||||
if DraftGeomUtils.isCoplanar(shape.Faces):
|
||||
shape = DraftGeomUtils.concatenate(shape)
|
||||
obj.Shape = shape
|
||||
p = []
|
||||
for v in shape.Vertexes: p.append(v.Point)
|
||||
if obj.Points != p: obj.Points = p
|
||||
elif obj.Points:
|
||||
if obj.Points[0] == obj.Points[-1]:
|
||||
if not obj.Closed: obj.Closed = True
|
||||
obj.Points.pop()
|
||||
if obj.Closed and (len(obj.Points) > 2):
|
||||
pts = obj.Points
|
||||
if hasattr(obj,"Subdivisions"):
|
||||
if obj.Subdivisions > 0:
|
||||
npts = []
|
||||
for i in range(len(pts)):
|
||||
p1 = pts[i]
|
||||
npts.append(pts[i])
|
||||
if i == len(pts)-1:
|
||||
p2 = pts[0]
|
||||
else:
|
||||
p2 = pts[i+1]
|
||||
v = p2.sub(p1)
|
||||
v = DraftVecUtils.scaleTo(v,v.Length/(obj.Subdivisions+1))
|
||||
for j in range(obj.Subdivisions):
|
||||
npts.append(p1.add(App.Vector(v).multiply(j+1)))
|
||||
pts = npts
|
||||
shape = Part.makePolygon(pts+[pts[0]])
|
||||
if "ChamferSize" in obj.PropertiesList:
|
||||
if obj.ChamferSize.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.ChamferSize.Value,chamfer=True)
|
||||
if w:
|
||||
shape = w
|
||||
if "FilletRadius" in obj.PropertiesList:
|
||||
if obj.FilletRadius.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.FilletRadius.Value)
|
||||
if w:
|
||||
shape = w
|
||||
try:
|
||||
if hasattr(obj,"MakeFace"):
|
||||
if obj.MakeFace:
|
||||
shape = Part.Face(shape)
|
||||
else:
|
||||
shape = Part.Face(shape)
|
||||
except Part.OCCError:
|
||||
pass
|
||||
else:
|
||||
edges = []
|
||||
pts = obj.Points[1:]
|
||||
lp = obj.Points[0]
|
||||
for p in pts:
|
||||
if not DraftVecUtils.equals(lp,p):
|
||||
if hasattr(obj,"Subdivisions"):
|
||||
if obj.Subdivisions > 0:
|
||||
npts = []
|
||||
v = p.sub(lp)
|
||||
v = DraftVecUtils.scaleTo(v,v.Length/(obj.Subdivisions+1))
|
||||
edges.append(Part.LineSegment(lp,lp.add(v)).toShape())
|
||||
lv = lp.add(v)
|
||||
for j in range(obj.Subdivisions):
|
||||
edges.append(Part.LineSegment(lv,lv.add(v)).toShape())
|
||||
lv = lv.add(v)
|
||||
else:
|
||||
edges.append(Part.LineSegment(lp,p).toShape())
|
||||
else:
|
||||
edges.append(Part.LineSegment(lp,p).toShape())
|
||||
lp = p
|
||||
try:
|
||||
shape = Part.Wire(edges)
|
||||
except Part.OCCError:
|
||||
print("Error wiring edges")
|
||||
shape = None
|
||||
if "ChamferSize" in obj.PropertiesList:
|
||||
if obj.ChamferSize.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.ChamferSize.Value,chamfer=True)
|
||||
if w:
|
||||
shape = w
|
||||
if "FilletRadius" in obj.PropertiesList:
|
||||
if obj.FilletRadius.Value != 0:
|
||||
w = DraftGeomUtils.filletWire(shape,obj.FilletRadius.Value)
|
||||
if w:
|
||||
shape = w
|
||||
if shape:
|
||||
obj.Shape = shape
|
||||
if hasattr(obj,"Area") and hasattr(shape,"Area"):
|
||||
obj.Area = shape.Area
|
||||
if hasattr(obj,"Length"):
|
||||
obj.Length = shape.Length
|
||||
|
||||
obj.Placement = plm
|
||||
obj.positionBySupport()
|
||||
self.onChanged(obj,"Placement")
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "Start":
|
||||
pts = obj.Points
|
||||
invpl = App.Placement(obj.Placement).inverse()
|
||||
realfpstart = invpl.multVec(obj.Start)
|
||||
if pts:
|
||||
if pts[0] != realfpstart:
|
||||
pts[0] = realfpstart
|
||||
obj.Points = pts
|
||||
|
||||
elif prop == "End":
|
||||
pts = obj.Points
|
||||
invpl = App.Placement(obj.Placement).inverse()
|
||||
realfpend = invpl.multVec(obj.End)
|
||||
if len(pts) > 1:
|
||||
if pts[-1] != realfpend:
|
||||
pts[-1] = realfpend
|
||||
obj.Points = pts
|
||||
|
||||
elif prop == "Length":
|
||||
if obj.Shape and not obj.Shape.isNull():
|
||||
if obj.Length.Value != obj.Shape.Length:
|
||||
if len(obj.Points) == 2:
|
||||
v = obj.Points[-1].sub(obj.Points[0])
|
||||
v = DraftVecUtils.scaleTo(v,obj.Length.Value)
|
||||
obj.Points = [obj.Points[0],obj.Points[0].add(v)]
|
||||
|
||||
elif prop == "Placement":
|
||||
pl = App.Placement(obj.Placement)
|
||||
if len(obj.Points) >= 2:
|
||||
displayfpstart = pl.multVec(obj.Points[0])
|
||||
displayfpend = pl.multVec(obj.Points[-1])
|
||||
if obj.Start != displayfpstart:
|
||||
obj.Start = displayfpstart
|
||||
if obj.End != displayfpend:
|
||||
obj.End = displayfpend
|
||||
|
||||
|
||||
_Wire = Wire
|
||||
160
src/Mod/Draft/draftviewproviders/view_wire.py
Normal file
160
src/Mod/Draft/draftviewproviders/view_wire.py
Normal file
@@ -0,0 +1,160 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * Copyright (c) 2019 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the view provider code for Draft wire related objects.
|
||||
"""
|
||||
## @package view_base
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the view provider code for Draft objects like\
|
||||
# Line, Polyline, BSpline, BezCurve.
|
||||
|
||||
|
||||
from pivy import coin
|
||||
from PySide import QtCore
|
||||
from PySide import QtGui
|
||||
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
|
||||
import draftutils.utils as utils
|
||||
import draftutils.gui_utils as gui_utils
|
||||
import DraftVecUtils
|
||||
import DraftGeomUtils
|
||||
|
||||
from draftviewproviders.view_base import ViewProviderDraft
|
||||
|
||||
|
||||
class ViewProviderWire(ViewProviderDraft):
|
||||
"""A base View Provider for the Wire object"""
|
||||
def __init__(self, vobj):
|
||||
super(ViewProviderWire, self).__init__(vobj)
|
||||
|
||||
_tip = "Displays a Dimension symbol at the end of the wire"
|
||||
vobj.addProperty("App::PropertyBool", "EndArrow",
|
||||
"Draft", QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "Arrow size"
|
||||
vobj.addProperty("App::PropertyLength", "ArrowSize",
|
||||
"Draft", QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
_tip = "Arrow type"
|
||||
vobj.addProperty("App::PropertyEnumeration", "ArrowType",
|
||||
"Draft", QT_TRANSLATE_NOOP("App::Property", _tip))
|
||||
|
||||
vobj.ArrowSize = utils.get_param("arrowsize",0.1)
|
||||
vobj.ArrowType = utils.ARROW_TYPES
|
||||
vobj.ArrowType = utils.ARROW_TYPES[utils.get_param("dimsymbol",0)]
|
||||
|
||||
def attach(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
col = coin.SoBaseColor()
|
||||
col.rgb.setValue(vobj.LineColor[0],vobj.LineColor[1],vobj.LineColor[2])
|
||||
self.coords = coin.SoTransform()
|
||||
self.pt = coin.SoSeparator()
|
||||
self.pt.addChild(col)
|
||||
self.pt.addChild(self.coords)
|
||||
self.symbol = gui_utils.dim_symbol()
|
||||
self.pt.addChild(self.symbol)
|
||||
super(ViewProviderWire, self).attach(vobj)
|
||||
self.onChanged(vobj,"EndArrow")
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
if prop == "Points":
|
||||
if obj.Points:
|
||||
p = obj.Points[-1]
|
||||
if hasattr(self,"coords"):
|
||||
self.coords.translation.setValue((p.x,p.y,p.z))
|
||||
if len(obj.Points) >= 2:
|
||||
v1 = obj.Points[-2].sub(obj.Points[-1])
|
||||
if not DraftVecUtils.isNull(v1):
|
||||
v1.normalize()
|
||||
_rot = coin.SbRotation()
|
||||
_rot.setValue(coin.SbVec3f(1, 0, 0), coin.SbVec3f(v1[0], v1[1], v1[2]))
|
||||
self.coords.rotation.setValue(_rot)
|
||||
return
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
if prop in ["EndArrow","ArrowSize","ArrowType","Visibility"]:
|
||||
rn = vobj.RootNode
|
||||
if hasattr(self,"pt") and hasattr(vobj,"EndArrow"):
|
||||
if vobj.EndArrow and vobj.Visibility:
|
||||
self.pt.removeChild(self.symbol)
|
||||
s = utils.ARROW_TYPES.index(vobj.ArrowType)
|
||||
self.symbol = gui_utils.dim_symbol(s)
|
||||
self.pt.addChild(self.symbol)
|
||||
self.updateData(vobj.Object,"Points")
|
||||
if hasattr(vobj,"ArrowSize"):
|
||||
s = vobj.ArrowSize
|
||||
else:
|
||||
s = utils.get_param("arrowsize",0.1)
|
||||
self.coords.scaleFactor.setValue((s,s,s))
|
||||
rn.addChild(self.pt)
|
||||
else:
|
||||
if self.symbol:
|
||||
if self.pt.findChild(self.symbol) != -1:
|
||||
self.pt.removeChild(self.symbol)
|
||||
if rn.findChild(self.pt) != -1:
|
||||
rn.removeChild(self.pt)
|
||||
|
||||
if prop in ["LineColor"]:
|
||||
if hasattr(self, "pt"):
|
||||
self.pt[0].rgb.setValue(vobj.LineColor[0],vobj.LineColor[1],vobj.LineColor[2])
|
||||
|
||||
super(ViewProviderWire, self).onChanged(vobj, prop)
|
||||
return
|
||||
|
||||
def claimChildren(self):
|
||||
if hasattr(self.Object,"Base"):
|
||||
return [self.Object.Base,self.Object.Tool]
|
||||
return []
|
||||
|
||||
def setupContextMenu(self,vobj,menu):
|
||||
action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Edit.svg"),
|
||||
"Flatten this wire",
|
||||
menu)
|
||||
QtCore.QObject.connect(action1,
|
||||
QtCore.SIGNAL("triggered()"),
|
||||
self.flatten)
|
||||
menu.addAction(action1)
|
||||
|
||||
def flatten(self):
|
||||
if hasattr(self,"Object"):
|
||||
if len(self.Object.Shape.Wires) == 1:
|
||||
fw = DraftGeomUtils.flattenWire(self.Object.Shape.Wires[0])
|
||||
points = [v.Point for v in fw.Vertexes]
|
||||
if len(points) == len(self.Object.Points):
|
||||
if points != self.Object.Points:
|
||||
App.ActiveDocument.openTransaction("Flatten wire")
|
||||
Gui.doCommand("FreeCAD.ActiveDocument." +
|
||||
self.Object.Name +
|
||||
".Points=" +
|
||||
str(points).replace("Vector", "FreeCAD.Vector").replace(" " , ""))
|
||||
App.ActiveDocument.commitTransaction()
|
||||
|
||||
else:
|
||||
_msg = "This Wire is already flat"
|
||||
App.Console.PrintMessage(QT_TRANSLATE_NOOP("Draft", _msg) + "\n")
|
||||
|
||||
|
||||
_ViewProviderWire = ViewProviderWire
|
||||
Reference in New Issue
Block a user