Square to round transition
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Be nice to others! Respect the FreeCAD code of conduct!
Re: Square to round transition
I am locked out, cannot type in placement or position for some reason.
- Attachments
-
- Screenshot 2022-07-19 220841.png (7.86 KiB) Viewed 1094 times
-
- Veteran
- Posts: 3180
- Joined: Thu Sep 24, 2020 10:31 pm
- Location: Hawaii
- Contact:
Re: Square to round transition
OK. You have it "attached" to the XY-Plane. Edit the attachment offset instead.
BTW, if you enclose the file there’s less guessing about the problem.
BTW, if you enclose the file there’s less guessing about the problem.
-
- Veteran
- Posts: 3180
- Joined: Thu Sep 24, 2020 10:31 pm
- Location: Hawaii
- Contact:
Re: Square to round transition
I tried using Part Design's loft to a point (FreeCAD 0.20+). At least the way that I did it, it was more complicated and the results were the same.
Part Design only creates solids, so after creating a suitable lofted solid:
I did a Draft Downgrade to faces (which mysteriously gets rid of the body object somehow), selected the outside faces and Draft upgraded to a shell:
Then, as before to flatten the shell, I had to go via creating a mesh and Mesh Design|Unwrap Mesh.
This gives a perfectly good cutting template, but if you extract vertex coordinates from it, you get a large number, even along the straight edges, because of the intermediate mesh resolution. This might be OK for CNC...
So, depending on your exact needs, it might be better to use the low level approach of the original Basic code, translated to Python, than using a spreadsheet driven FreeCAD model of the object.
The technical stumbling block to a totally clean solution is the unwrapping of the ruled curved faces without going through a mesh.
Part Design only creates solids, so after creating a suitable lofted solid:
I did a Draft Downgrade to faces (which mysteriously gets rid of the body object somehow), selected the outside faces and Draft upgraded to a shell:
Then, as before to flatten the shell, I had to go via creating a mesh and Mesh Design|Unwrap Mesh.
This gives a perfectly good cutting template, but if you extract vertex coordinates from it, you get a large number, even along the straight edges, because of the intermediate mesh resolution. This might be OK for CNC...
So, depending on your exact needs, it might be better to use the low level approach of the original Basic code, translated to Python, than using a spreadsheet driven FreeCAD model of the object.
The technical stumbling block to a totally clean solution is the unwrapping of the ruled curved faces without going through a mesh.
Re: Square to round transition
@edwilliams16 to practice I did a 1/4 transaction attached are some files with stages.
I had to to the 2 larges sections separate and the middle to faces the connect, then mesh, then unroll.
Note, this is why I prefer the above program that "auto" lays out a fitting flat to begin with, by just punching in a few parameters. It lay out in a blink of an eye. However I am trying to learn other techniques as well.
Also when I tried to unfold all from one mesh, it was way incorrect.
A big transition will need more segments, like 36, enclosed is one, and that is 48 inches, not mm.
I had to to the 2 larges sections separate and the middle to faces the connect, then mesh, then unroll.
Note, this is why I prefer the above program that "auto" lays out a fitting flat to begin with, by just punching in a few parameters. It lay out in a blink of an eye. However I am trying to learn other techniques as well.
Also when I tried to unfold all from one mesh, it was way incorrect.
A big transition will need more segments, like 36, enclosed is one, and that is 48 inches, not mm.
-
- Veteran
- Posts: 3180
- Joined: Thu Sep 24, 2020 10:31 pm
- Location: Hawaii
- Contact:
Re: Square to round transition
It seems when the faces were flat triangles, the mesh triangulation does no subdivision, so your route of approximating the circle with a polygon works well with the mesh unrolling.
Here's a simple script that transitions a square to an n-agon. I just did a quarter, because of the symmetry. If you want to generalize it to tilted or offset n-agons, or rectangles instead of squares, it's straightforward...
Just paste the (edited) script into the python console.
Here's a simple script that transitions a square to an n-agon. I just did a quarter, because of the symmetry. If you want to generalize it to tilted or offset n-agons, or rectangles instead of squares, it's straightforward...
Just paste the (edited) script into the python console.
Code: Select all
import Part, Mesh, MeshPart, PartGui
import FreeCADGui as Gui
import math
def printVertices(vs):
App.Console.PrintMessage('Template Vertices')
for i, v in enumerate(vs):
App.Console.PrintMessage(f'{i}: ({v.x:.2f},{v.y:.2f})\n')
doc = App.ActiveDocument
#square on xy-plane, centered at origin: work in first quadrant
V3 = App.Vector
inchtomm = 25.4
####inputs
squareSide = 40 * inchtomm
height = 15 * inchtomm
radius = 15 * inchtomm
nSides = 8
####
sV = [squareSide/2*V3(*v) for v in [(1,0,0), (1, 1, 0), (0, 1, 0)]]
# sV[2] sV[1]
#
# O sV[0]
# N-sided quarter circle
thetas = [(math.pi / 2 ) * j/nSides for j in range(nSides + 1)]
cV = [V3(radius * math.cos(t), radius * math.sin(t), height) for t in thetas]
firstFace = Part.Face(Part.makePolygon([sV[0], cV[0], sV[1], sV[0]]))
#Part.show(firstFace)
faceList = [firstFace]
lastFace = Part.Face(Part.makePolygon([sV[2], cV[-1], sV[1], sV[2]]))
#Part.show(lastFace)
for j in range(nSides):
f = Part.Face(Part.makePolygon([sV[1], cV[j], cV[j+1], sV[1]]))
#Part.show(f)
faceList.append(f)
faceList.append(lastFace)
shell = Part.Shell(faceList)
Part.show(shell, "quarterShell")
mesh = doc.addObject('Mesh::Feature','Mesh')
mesh.Mesh=MeshPart.meshFromShape(Shape=shell, LinearDeflection=0.1, AngularDeflection=0.523599, Relative=False)
mesh.Label="Shape (Meshed)"
Gui.Selection.addSelection(doc.Name, 'Mesh')
Gui.runCommand('MeshPart_CreateFlatMesh',0)
template = doc.getObject('Shape')
template.Label = 'Template'
templateVertices = [v.Point for v in template.Shape.Vertexes]
printVertices(templateVertices)
- Attachments
-
- Screen Shot 2022-07-20 at 3.10.56 PM.png (15.62 KiB) Viewed 941 times
-
- Veteran
- Posts: 3180
- Joined: Thu Sep 24, 2020 10:31 pm
- Location: Hawaii
- Contact:
Re: Square to round transition
Removed the Gui dependence of the script.
Code: Select all
import numpy as np
import Part, Mesh, MeshPart
import math
import numpy as np
import flatmesh
def printVertices(vs):
App.Console.PrintMessage('Template Vertices')
for i, v in enumerate(vs):
App.Console.PrintMessage(f'{i}: ({v.x:.2f},{v.y:.2f})\n')
def flattenMesh(obj):
#https://github.com/FreeCAD/FreeCAD/blob/0d0bd1168bb96ded8dfe5ab3ca60588dec5d2949/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py
points = np.array([[i.x, i.y, i.z] for i in obj.Mesh.Points])
faces = np.array([list(i) for i in obj.Mesh.Topology[1]])
flattener = flatmesh.FaceUnwrapper(points, faces)
flattener.findFlatNodes(5, 0.95)
boundaries = flattener.getFlatBoundaryNodes()
wires = []
for edge in boundaries:
pi = Part.makePolygon([App.Vector(*node) for node in edge])
wires.append(Part.Wire(pi))
return wires
doc = App.ActiveDocument
#square on xy-plane, centered at origin: work in first quadrant
V3 = App.Vector
inchtomm = 25.4
####inputs
squareSide = 40 * inchtomm
height = 15 * inchtomm
radius = 15 * inchtomm
nSides = 8
####
sV = [squareSide/2*V3(*v) for v in [(1,0,0), (1, 1, 0), (0, 1, 0)]]
# sV[2] sV[1]
#
# O sV[0]
# N-sided quarter circle
thetas = [(math.pi / 2 ) * j/nSides for j in range(nSides + 1)]
cV = [V3(radius * math.cos(t), radius * math.sin(t), height) for t in thetas]
firstFace = Part.Face(Part.makePolygon([sV[0], cV[0], sV[1], sV[0]]))
#Part.show(firstFace)
faceList = [firstFace]
lastFace = Part.Face(Part.makePolygon([sV[2], cV[-1], sV[1], sV[2]]))
#Part.show(lastFace)
for j in range(nSides):
f = Part.Face(Part.makePolygon([sV[1], cV[j], cV[j+1], sV[1]]))
#Part.show(f)
faceList.append(f)
faceList.append(lastFace)
shell = Part.Shell(faceList)
Part.show(shell, "quarterShell")
mesh = doc.addObject('Mesh::Feature','Mesh')
mesh.Mesh=MeshPart.meshFromShape(Shape=shell, LinearDeflection=0.1, AngularDeflection=0.523599, Relative=False)
mesh.Label="QuarterShell (Meshed)"
#Gui.Selection.addSelection(doc.Name, 'Mesh')
#Gui.runCommand('MeshPart_CreateFlatMesh',0)
wires = flattenMesh(mesh)
template = Part.show(wires[0], "Template") #only one outline here
#template = doc.getObject('Template')
#template.Label = 'Template'
templateVertices = [v.Point for v in template.Shape.Vertexes]
printVertices(templateVertices
Re: Square to round transition
I will experiment around with both. I am not advanced enough to figure out how to do inputs, the older basicad program I did around 1997, been a while.
-
- Veteran
- Posts: 3180
- Joined: Thu Sep 24, 2020 10:31 pm
- Location: Hawaii
- Contact:
Re: Square to round transition
For now you can just edit
One can always add some dialog boxes or a spreadsheet input later.
It was easy enough to allow the circular opening to be tilted and/or offset.
The vertex coordinates are output to the Report window. They should probably be rotated and translated in some way for your application. ie where should the origin be and what alignment?
Code: Select all
####inputs
squareSide = 40 * inchtomm
height = 15 * inchtomm
radius = 15 * inchtomm
nSides = 8
####
It was easy enough to allow the circular opening to be tilted and/or offset.
Code: Select all
import numpy as np
import Part, Mesh, MeshPart
import math
import numpy as np
import flatmesh
def printVertices(vs):
App.Console.PrintMessage('Template Vertices')
for i, v in enumerate(vs):
App.Console.PrintMessage(f'{i}: ({v.x:.2f},{v.y:.2f})\n')
def flattenMesh(obj):
#https://github.com/FreeCAD/FreeCAD/blob/0d0bd1168bb96ded8dfe5ab3ca60588dec5d2949/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py
points = np.array([[i.x, i.y, i.z] for i in obj.Mesh.Points])
faces = np.array([list(i) for i in obj.Mesh.Topology[1]])
flattener = flatmesh.FaceUnwrapper(points, faces)
flattener.findFlatNodes(5, 0.95)
boundaries = flattener.getFlatBoundaryNodes()
wires = []
for edge in boundaries:
pi = Part.makePolygon([App.Vector(*node) for node in edge])
wires.append(Part.Wire(pi))
return wires
doc = App.ActiveDocument
#square on xy-plane, centered at origin:
V3 = App.Vector
inchtomm = 25.4
####inputs
squareSide = 40 * inchtomm
height = 15 * inchtomm #circle center location
xoffset = 3 *inchtomm
yoffset = 4 * inchtomm
circleRotationAngle = 20 #degrees
circleRotationAxis = V3(1, 0, 0)
radius = 15 * inchtomm
nSides = 8
####
#sV = [squareSide/2*V3(*v) for v in [(1,0,0), (1, 1, 0), (0, 1, 0)]]
eps =1e-6
sV = [squareSide/2*V3(*v) for v in [(1,0,0), (1, 1, 0), (0, 1, 0),(-1,1,0), (-1, 0, 0), (-1, -1, 0), (0, -1, 0), (1,-1, 0), (1-eps,0,0)]]
# sv[3] sV[2] sV[1]
#
# sv[4] O sV[0], sv[8] seam
#
# sv[5] sV[6] sV[7]
# 4N-sided quarter circle
thetas = [2 * math.pi * j/(4 * nSides) for j in range(4*nSides + 1)]
thetas[-1] -= eps #seam
#create and locate circle
cV2 = [V3(radius * math.cos(t), radius * math.sin(t), 0) for t in thetas]
pl = App.Placement(V3(xoffset, yoffset, height), App.Rotation(circleRotationAxis, circleRotationAngle))
cV = [pl.multVec(v) for v in cV2]
faceList = []
for k in range(4):
face = Part.Face(Part.makePolygon([sV[2*k], cV[nSides*k], sV[2*k + 1], sV[2*k]]))
#Part.show(face)
faceList.append(face)
face = Part.Face(Part.makePolygon([sV[2*k + 1], cV[nSides*(k + 1)], sV[2*k + 2], sV[2*k + 1]]))
#Part.show(face)
faceList.append(face)
for k in range(4):
for j in range(nSides):
f = Part.Face(Part.makePolygon([sV[2*k +1], cV[nSides*k +j], cV[nSides*k + j+1], sV[2*k +1]]))
#Part.show(f)
faceList.append(f)
shell = Part.Shell(faceList)
Part.show(shell, "QuarterShell")
mesh = doc.addObject('Mesh::Feature','Mesh')
mesh.Mesh=MeshPart.meshFromShape(Shape=shell, LinearDeflection=0.1, AngularDeflection=0.523599, Relative=False)
mesh.Label="QuarterShell (Meshed)"
#Gui.Selection.addSelection(doc.Name, 'Mesh')
#Gui.runCommand('MeshPart_CreateFlatMesh',0)
wires = flattenMesh(mesh)
template = Part.show(wires[0], "Template") #only one outline here
#template = doc.getObject('Template')
#template.Label = 'Template'
templateVertices = [v.Point for v in template.Shape.Vertexes]
printVertices(templateVertices)
Re: Square to round transition
@edwilliams16 Holy Molly that is great. Me being new, I would have never figured out that, lines like:
I am hoping there is one more you and @johnwang might help with. Late now, I will post it tomorrow, please look for it.
Also, if you get a chance, please make the above a Macro anyone can use in the Freecad program, only if you have time.
The next program I think may even throw you fora loop.
Edit::
Would the above code still work if it was rectangular to round and not just Square?
I understand the geometry, but not the freecad python yet. You are real good at this.face = Part.Face(Part.makePolygon([sV[2*k], cV[nSides*k], sV[2*k + 1], sV[2*k]]))
abd
mesh.Mesh=MeshPart.meshFromShape(Shape=shell, LinearDeflection=0.1, AngularDeflection=0.523599, Relative=False)
I am hoping there is one more you and @johnwang might help with. Late now, I will post it tomorrow, please look for it.
Also, if you get a chance, please make the above a Macro anyone can use in the Freecad program, only if you have time.
The next program I think may even throw you fora loop.
Edit::
Would the above code still work if it was rectangular to round and not just Square?
Re: Square to round transition
@edwilliams16 in case you missed edited answer, could you tweak the python program an have rectangular to round also?
Also I am uploading a file where I tried the same techniques of upgrading faces, but did not get expect results, pleas have a look.
Also I am uploading a file where I tried the same techniques of upgrading faces, but did not get expect results, pleas have a look.
- Attachments
-
- ms2_unexpected.FCStd
- (11.22 KiB) Downloaded 14 times
-
- ms2_newtry.FCStd
- (13.11 KiB) Downloaded 14 times