Wrapping a sketch around a cylinder
Forum rules
Be nice to others! Read the FreeCAD code of conduct!
Be nice to others! Read the FreeCAD code of conduct!
Re: Wrapping a sketch around a cylinder
Hi Quick61,
Here how to install it in your freecad (i've test it over 0.16 and 0.17RC successfully):
Copy the code and save it as a .FCMacro files (eg. PolarExtrude.FCMacro) in your user freecad macro dir (windows: c:\users\"yourusername"\AppData\Roaming\FreeCAD\Macro linux: ~/.freecad/macro (I think))
In freecad select one or more sketch (Highlight it in the tree) and click on the macro menu at top --> macro ... --> Select PolarExtrude.FCMacro and click execute.
Voila! you've done.
After you could modify the radius and extrusion thickness on the generated object properties.
If you wish you could also add an icon to a toolbar for easier access...
Here how to install it in your freecad (i've test it over 0.16 and 0.17RC successfully):
Copy the code and save it as a .FCMacro files (eg. PolarExtrude.FCMacro) in your user freecad macro dir (windows: c:\users\"yourusername"\AppData\Roaming\FreeCAD\Macro linux: ~/.freecad/macro (I think))
In freecad select one or more sketch (Highlight it in the tree) and click on the macro menu at top --> macro ... --> Select PolarExtrude.FCMacro and click execute.
Voila! you've done.
After you could modify the radius and extrusion thickness on the generated object properties.
If you wish you could also add an icon to a toolbar for easier access...
Re: Wrapping a sketch around a cylinder
Stonedge do you think this code could be easy modified to use it the other way around ?
Would be awsome to unwrappe a cirlce/curved face.I know there exist already some macros like.
-Macro Unroll Ruled Surface (seams to work only for predefined part objects like zylinders....but all other tested surfaces dont work)
-Macro Unfold Box (only for box)
-Macro Sheet Metal Unfolder (seams only for sheet metal objects..but i think some parts of the code are for surfaces to...maybe)
But nothing seams to work only for a curved surface.
I tested your code ....very cool...is it true that only multy sketch selection is possible and not draft object....so to use it you have to convert draft objects to sketch objects.
Would be awsome to unwrappe a cirlce/curved face.I know there exist already some macros like.
-Macro Unroll Ruled Surface (seams to work only for predefined part objects like zylinders....but all other tested surfaces dont work)
-Macro Unfold Box (only for box)
-Macro Sheet Metal Unfolder (seams only for sheet metal objects..but i think some parts of the code are for surfaces to...maybe)
But nothing seams to work only for a curved surface.
I tested your code ....very cool...is it true that only multy sketch selection is possible and not draft object....so to use it you have to convert draft objects to sketch objects.
Re: Wrapping a sketch around a cylinder
Could you give me an example of what you are trying to achieve? kind of what pepakura do? flatten a curve surface for 2d cutting?
That kind of flattening would normally generate cut over the face, it is what you looking for?
Stonedge
That kind of flattening would normally generate cut over the face, it is what you looking for?
Stonedge
Re: Wrapping a sketch around a cylinder
Here is an example what i try to achieve. I would say pepakura does the same but its for Mesh models (flat faces) and not for Curve Surfaces.
Unwrapping meshes with defined seams its not a problem in blender. The result is achieved with unroll in Rhino.
Hope it gives you an idea what i am looking for.
Unwrapping meshes with defined seams its not a problem in blender. The result is achieved with unroll in Rhino.
Hope it gives you an idea what i am looking for.
Re: Wrapping a sketch around a cylinder
Ok After playing a little(... a lot...) with that macro it seem that it have some issue with circle.... most of the time playing lightly with the sketch fix the issue... but I've finnally hit the limit of that trick with one of my design...
So I've use that occasion to fire up my python debugger and start debugging... finally found it Float Precision issue with a direct equallity comparaison!
Here the Change:
if (sp.x == ep.x): --> if (round(sp.x,3) == round(ep.x,3)):
and
elif (sp.y == ep.y: --> elif (round(sp.y,3) == round(ep.y,3)):
and Here the completed fixed macro:
PolarExtrude.FCMacro
Now this Macro Work very well with complex sketch...
but don't forget that it remain some limitation:
since it use loft, the sketch must be a close face ( no hole... see loft documentation)
Currently unable to made a design do more than 180 deg... you must do it using 2 or more sketch
Again, all the credit go to original author!
Enjoy
Stonedge
So I've use that occasion to fire up my python debugger and start debugging... finally found it Float Precision issue with a direct equallity comparaison!
Here the Change:
if (sp.x == ep.x): --> if (round(sp.x,3) == round(ep.x,3)):
and
elif (sp.y == ep.y: --> elif (round(sp.y,3) == round(ep.y,3)):
and Here the completed fixed macro:
PolarExtrude.FCMacro
Code: Select all
from __future__ import division # allows floating point division from integers
import FreeCAD, FreeCADGui
from FreeCAD import Base
import Part
import math
def GetObjectByLabel(objectName):
for oo in FreeCAD.ActiveDocument.Objects:
if oo.Label == objectName:
return oo
return None
def getPointOnCylinder(ax, ay, Radius):
angle = ax/Radius
result = (math.cos(angle)*Radius, math.sin(angle)*Radius, ay)
return result
def WrapBSpline(bspline, Radius, XScale):
poles = bspline.getPoles()
newpoles=[]
for pp in poles:
newpoles.append(getPointOnCylinder(pp[0]*XScale, pp[1], Radius))
newbspline = bspline
newbspline.buildFromPolesMultsKnots(newpoles, bspline.getMultiplicities(), bspline.getKnots(), bspline.isPeriodic(), bspline.Degree, bspline.getWeights())
return newbspline.toShape()
def WrapSketch(Sketch, Radius, XScale):
Edges = []
for gg in Sketch.Geometry:
if (gg.Construction):
continue
if str(type(gg)) == "<type 'Part.GeomArcOfCircle'>":
bspline = gg.toBSpline()
Edges.append(WrapBSpline(bspline, Radius, XScale))
elif str(type(gg)) == "<type 'Part.GeomLineSegment'>":
sp = gg.StartPoint
ep = gg.EndPoint
if (sp.x > ep.x):
tt = sp
sp = ep
ep = tt
sp.x = sp.x*XScale
ep.x = ep.x*XScale
if (round(sp.x,3) == round(ep.x,3)):
Edges.append(Part.makeLine(getPointOnCylinder(sp.x, sp.y, Radius), getPointOnCylinder(ep.x, ep.y, Radius)))
elif (round(sp.y,3) == round(ep.y,3)):
Angle0 = sp.x/Radius*180/math.pi
Angle1 = ep.x/Radius*180/math.pi
cc = Part.makeCircle(Radius, Base.Vector(0, 0, gg.StartPoint.y), Base.Vector(0, 0, 1), Angle0, Angle1)
Edges.append(cc)
else:
hh = Part.makeHelix(2*abs(ep.y - sp.y)*math.pi/(abs(ep.x - sp.x)/Radius), abs(ep.y - sp.y), Radius, 0, (sp.y > ep.y))
if (sp.y > ep.y):
hh.rotate(Base.Vector(0,0,0), Base.Vector(0,0,1), ep.x/Radius*180/math.pi);
else:
hh.rotate(Base.Vector(0,0,0), Base.Vector(0,0,1), sp.x/Radius*180/math.pi);
hh.Placement.Base = Base.Vector(0, 0, min(sp.y, ep.y))
Edges.append(hh)
return Edges
class WrappedSketch:
def __init__(self, obj, SketchLabel = "", RuledRadius = 50, Thickness = 2):
PropertyGroup = "WrappedSketch";
obj.addProperty("App::PropertyString", "SketchLabel", PropertyGroup, "").SketchLabel = SketchLabel
obj.addProperty("App::PropertyFloat", "RuledRadius", PropertyGroup, "Radius for outer surface").RuledRadius = RuledRadius
obj.addProperty("App::PropertyFloat", "Thickness", PropertyGroup, "Thickness of extrusion").Thickness = Thickness
obj.Proxy = self
def execute(self, obj):
Sketch = GetObjectByLabel(obj.SketchLabel)
if (Sketch == None):
return
InnerRadius = obj.RuledRadius - obj.Thickness
Edges = WrapSketch(Sketch, obj.RuledRadius, 1.0)
Shape = Part.makeCompound(Edges)
Face1 = Part.makeFilledFace(Part.__sortEdges__(Shape.Edges))
Edges = WrapSketch(Sketch, InnerRadius, InnerRadius/obj.RuledRadius)
Shape = Part.makeCompound(Edges)
Face2 = Part.makeFilledFace(Part.__sortEdges__(Shape.Edges))
loft = Part.makeLoft([Face1.OuterWire, Face2.OuterWire], True, True);
obj.Shape = loft.removeSplitter()
def makeWrappedSketch():
if FreeCAD.ActiveDocument is None:
return
aSketchLabel = ""
selections=FreeCAD.Gui.Selection.getSelectionEx()
if len(selections) > 0:
for selObject in selections:
aSketchLabel = ""
if str(type(selObject.Object)) == "<type 'Sketcher.SketchObject'>":
aSketchLabel = selObject.Object.Label
FreeCAD.Console.PrintMessage("Processing:"+ aSketchLabel +"\n")
a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","WrappedSketch")
WrappedSketch(a, SketchLabel=aSketchLabel)
a.ViewObject.Proxy=0 # just set it to something different from None (this assignment is needed to run an internal notification)
FreeCAD.ActiveDocument.recompute()
FreeCADGui.ActiveDocument.ActiveView.fitAll()
return a
FreeCAD.Console.PrintMessage("makeWrappedSketch Start"+"\n")
makeWrappedSketch()
FreeCAD.Console.PrintMessage("makeWrappedSketch End"+"\n")
but don't forget that it remain some limitation:
since it use loft, the sketch must be a close face ( no hole... see loft documentation)
Currently unable to made a design do more than 180 deg... you must do it using 2 or more sketch
Again, all the credit go to original author!
Enjoy
Stonedge
- DeepSOIC
- Veteran
- Posts: 7896
- Joined: Fri Aug 29, 2014 12:45 am
- Location: used to be Saint-Petersburg, Russia
Re: Wrapping a sketch around a cylinder
This is still an incorrect way of comparing floats. Because round(0.0005000001, 3) is not equal to round(0.0004999999, 3)Stonedge wrote:round(sp.x,3) == round(ep.x,3)
Use, for example, abs(sp.x - ep.x) < tolerance
Re: Wrapping a sketch around a cylinder
Thanks DeepSOIC for the hint!
I know it was a quick dirty fix/hack!
So here is the Correctly Fixed Version...BTW I've set the tolerance to 0.001 (test)
Stonedge
I know it was a quick dirty fix/hack!
So here is the Correctly Fixed Version...BTW I've set the tolerance to 0.001 (test)
Stonedge
Code: Select all
from __future__ import division # allows floating point division from integers
import FreeCAD, FreeCADGui
from FreeCAD import Base
import Part
import math
def GetObjectByLabel(objectName):
for oo in FreeCAD.ActiveDocument.Objects:
if oo.Label == objectName:
return oo
return None
def getPointOnCylinder(ax, ay, Radius):
angle = ax/Radius
result = (math.cos(angle)*Radius, math.sin(angle)*Radius, ay)
return result
def WrapBSpline(bspline, Radius, XScale):
poles = bspline.getPoles()
newpoles=[]
for pp in poles:
newpoles.append(getPointOnCylinder(pp[0]*XScale, pp[1], Radius))
newbspline = bspline
newbspline.buildFromPolesMultsKnots(newpoles, bspline.getMultiplicities(), bspline.getKnots(), bspline.isPeriodic(), bspline.Degree, bspline.getWeights())
return newbspline.toShape()
def WrapSketch(Sketch, Radius, XScale):
Edges = []
for gg in Sketch.Geometry:
if (gg.Construction):
continue
if str(type(gg)) == "<type 'Part.GeomArcOfCircle'>":
bspline = gg.toBSpline()
Edges.append(WrapBSpline(bspline, Radius, XScale))
elif str(type(gg)) == "<type 'Part.GeomLineSegment'>":
sp = gg.StartPoint
ep = gg.EndPoint
if (sp.x > ep.x):
tt = sp
sp = ep
ep = tt
sp.x = sp.x*XScale
ep.x = ep.x*XScale
if (abs(sp.x - ep.x) < 0.001):
Edges.append(Part.makeLine(getPointOnCylinder(sp.x, sp.y, Radius), getPointOnCylinder(ep.x, ep.y, Radius)))
elif (abs(sp.y - ep.y) < 0.001):
Angle0 = sp.x/Radius*180/math.pi
Angle1 = ep.x/Radius*180/math.pi
cc = Part.makeCircle(Radius, Base.Vector(0, 0, gg.StartPoint.y), Base.Vector(0, 0, 1), Angle0, Angle1)
Edges.append(cc)
else:
hh = Part.makeHelix(2*abs(ep.y - sp.y)*math.pi/(abs(ep.x - sp.x)/Radius), abs(ep.y - sp.y), Radius, 0, (sp.y > ep.y))
if (sp.y > ep.y):
hh.rotate(Base.Vector(0,0,0), Base.Vector(0,0,1), ep.x/Radius*180/math.pi);
else:
hh.rotate(Base.Vector(0,0,0), Base.Vector(0,0,1), sp.x/Radius*180/math.pi);
hh.Placement.Base = Base.Vector(0, 0, min(sp.y, ep.y))
Edges.append(hh)
return Edges
class WrappedSketch:
def __init__(self, obj, SketchLabel = "", RuledRadius = 50, Thickness = 2):
PropertyGroup = "WrappedSketch";
obj.addProperty("App::PropertyString", "SketchLabel", PropertyGroup, "").SketchLabel = SketchLabel
obj.addProperty("App::PropertyFloat", "RuledRadius", PropertyGroup, "Radius for outer surface").RuledRadius = RuledRadius
obj.addProperty("App::PropertyFloat", "Thickness", PropertyGroup, "Thickness of extrusion").Thickness = Thickness
obj.Proxy = self
def execute(self, obj):
Sketch = GetObjectByLabel(obj.SketchLabel)
if (Sketch == None):
return
InnerRadius = obj.RuledRadius - obj.Thickness
Edges = WrapSketch(Sketch, obj.RuledRadius, 1.0)
Shape = Part.makeCompound(Edges)
Face1 = Part.makeFilledFace(Part.__sortEdges__(Shape.Edges))
Edges = WrapSketch(Sketch, InnerRadius, InnerRadius/obj.RuledRadius)
Shape = Part.makeCompound(Edges)
Face2 = Part.makeFilledFace(Part.__sortEdges__(Shape.Edges))
loft = Part.makeLoft([Face1.OuterWire, Face2.OuterWire], True, True);
obj.Shape = loft.removeSplitter()
def makeWrappedSketch():
if FreeCAD.ActiveDocument is None:
return
aSketchLabel = ""
selections=FreeCAD.Gui.Selection.getSelectionEx()
if len(selections) > 0:
for selObject in selections:
aSketchLabel = ""
if str(type(selObject.Object)) == "<type 'Sketcher.SketchObject'>":
aSketchLabel = selObject.Object.Label
FreeCAD.Console.PrintMessage("Processing:"+ aSketchLabel +"\n")
a=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","WrappedSketch")
WrappedSketch(a, SketchLabel=aSketchLabel)
a.ViewObject.Proxy=0 # just set it to something different from None (this assignment is needed to run an internal notification)
FreeCAD.ActiveDocument.recompute()
FreeCADGui.ActiveDocument.ActiveView.fitAll()
return a
FreeCAD.Console.PrintMessage("makeWrappedSketch Start"+"\n")
makeWrappedSketch()
FreeCAD.Console.PrintMessage("makeWrappedSketch End"+"\n")
Re: Wrapping a sketch around a cylinder
OS: Windows 7
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.16.6704 (Git)
Build type: Release
Branch: releases/FreeCAD-0-16
Hash: 0c449d7e8f9b2b1fb93e3f8d1865e2f59d7ed253
Python version: 2.7.8
Qt version: 4.8.7
Coin version: 4.0.0a
OCC version: 6.8.0.oce-0.17
Hi Stonedge,
I have been trying to wrap an egg shape sketch around a cylinder using the macro you shared so kindly. I am getting some rather strange results. Have you any idea where I may be going wrong please? Any help greatly appreciated.
Oliver
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.16.6704 (Git)
Build type: Release
Branch: releases/FreeCAD-0-16
Hash: 0c449d7e8f9b2b1fb93e3f8d1865e2f59d7ed253
Python version: 2.7.8
Qt version: 4.8.7
Coin version: 4.0.0a
OCC version: 6.8.0.oce-0.17
Hi Stonedge,
I have been trying to wrap an egg shape sketch around a cylinder using the macro you shared so kindly. I am getting some rather strange results. Have you any idea where I may be going wrong please? Any help greatly appreciated.
Oliver
- Attachments
-
- Curved_egg_shape_0.1.FCStd
- (57.55 KiB) Downloaded 91 times
Re: Wrapping a sketch around a cylinder
You may look in the german forum: viewtopic.php?f=13&t=17983. microcelly2 has put considerable work in further development of the macro.
A Sketcher Lecture with in-depth information is available in English, auf Deutsch, en français, en español.
Re: Wrapping a sketch around a cylinder
Thanks Chris,
I tried with the macro from the German forum but the work flow was not clear. Pretty sure it is a small detail I am missing. I will wait to see if Stoneedge can save me from myself
Oliver
I tried with the macro from the German forum but the work flow was not clear. Pretty sure it is a small detail I am missing. I will wait to see if Stoneedge can save me from myself
Oliver