I've made this macro that can create quad meshes as a ruled surface between curves.
https://youtu.be/GkX37Bhy_p4
Can anyone help me improve this? Add it to the FEM gui somehow?
Any kind of interactive mesh generation is my goal here.
Anyone have any equivalencing scripts they'd care to contribute?
Did I do anything wrong in this macro? What fixes it?
Code: Select all
# There is a way to create an arc between points.
import FreeCAD
import Part
from FreeCAD import Base
import Fem
from math import pi as pi
def main():
# get selections
N_selections = 0
sel = []
for o in Gui.Selection.getSelectionEx():
for s in o.SubElementNames:
for s in o.SubObjects:
N_selections = N_selections + 1
sel.append(s)
# Check that there are the correct number of selections
if N_selections != 2:
print("Select Two Edges\n")
return
Curve_01 = sel[0]
Curve_02 = sel[1]
# Need to make Curve_01 and Curve_02
# It should be a priority to get these from a gui
# Populate, Create, and show Curve_1
#X1 = Base.Vector(0, 0, 0)
#Y1 = Base.Vector(1, 1, 0)
#Z1 = Base.Vector(2, 0.5, 0)
#arc = Part.Arc(X1, Y1, Z1)
#Curve_01 = arc.toShape()
#Part.show(Curve_01)
Arc_Length_01 = Curve_01.Length
# Populate, Create, and show Curve_2
#X2 = Base.Vector(0, 0, 6)
#Y2 = Base.Vector(1, 1, 6)
#Z2 = Base.Vector(2, 0, 6)
#arc = Part.Arc(X2, Y2, Z2)
#Curve_02 = arc.toShape()
#Part.show(Curve_02)
Arc_Length_02 = Curve_02.Length
# Can get document name with FreeCAD.ActiveDocument.Name
# Knowledge From Here
# https://wiki.freecadweb.org/Topological_data_scripting
# I can get a list of "N" points by calling 'valueAt' on "Arc_Length"
N_elms_X = 20
N_elms_Y = 20
# get the nodes on curve_01
Nodes_On_Curve_1 = get_nodes_from_curve(Curve_01, N_elms_X)
# get the nodes on curve_02
Nodes_On_Curve_2 = get_nodes_from_curve(Curve_02, N_elms_X)
# Make nodes by tracing the streamlines of the surface
nodes = make_nodes_of_ruled_mesh(Nodes_On_Curve_1, Nodes_On_Curve_2, N_elms_Y)
# Now to make the elements
E2N = make_elements_of_ruled_mesh(N_elms_X, N_elms_Y)
# Now have E2N and Nodes array
# Add all of the nodes to a container called "a"
a = Fem.FemMesh()
# add all of the nodes to container "a"
for i in range(len(nodes)):
a.addNode(nodes[i][0], nodes[i][1], nodes[i][2], nodes[i][3])
# add all of the elements to container "a"
for i in range(len(E2N)):
a.addFace([E2N[i][1], E2N[i][2], E2N[i][3], E2N[i][4]],E2N[i][0])
# Making it render correctly
obj = App.ActiveDocument.addObject("Fem::FemMeshObject", "a")
obj.FemMesh = a
obj.Placement.Base = FreeCAD.Vector(0, 0, 0)
obj.ViewObject.DisplayMode = "Faces, Wireframe & Nodes"
obj.ViewObject.BackfaceCulling = False
def make_elements_of_ruled_mesh(N_elms_X, N_elms_Y):
Nx = N_elms_X + 1
Ny = N_elms_Y + 1
EID = 0
E2N = []
for j in range(Ny):
for i in range(Nx):
NID = 1 + Nx*j + i
# skip rolling over elements
if i == (Nx - 1):
continue
if j == (Ny - 1):
continue
EID = EID + 1
N1 = NID
N2 = 1 + Nx*(j+1) + i
N3 = N2 + 1
N4 = N1 + 1
# E2N = [EID, N1, N2, N3, N4]
E2N.append([EID, N1, N2, N3, N4])
return E2N
def get_nodes_from_curve(Curve_Handle, N_elms):
Arc_Length = Curve_Handle.Length
nodes_on_curve = []
for i in range(N_elms+1):
dist_along = (i/N_elms)
# Is it this? This worked originally.
#dist_along = (i/N_elms)*Arc_Length
This_Node = Curve_Handle.valueAt(dist_along)
x = This_Node.x
y = This_Node.y
z = This_Node.z
nodes_on_curve.append([x, y, z])
return nodes_on_curve
def make_nodes_of_ruled_mesh(Nodes_1, Nodes_2, N_elms_Y):
# Make nodes by tracing the streamlines of the surface
nodes = []
# first set of nodes will be from Nodes_On_Curve_1
NID = 0
for i in range(len(Nodes_1)):
# Get coordinates of the node on Curve 1
x1 = Nodes_1[i][0]
y1 = Nodes_1[i][1]
z1 = Nodes_1[i][2]
# Get coordinates of the node on Curve 2
x2 = Nodes_2[i][0]
y2 = Nodes_2[i][1]
z2 = Nodes_2[i][2]
# current node will be a weighted average of coords
for j in range(N_elms_Y+1):
NID = NID + 1
x = (x2-x1)*(j/N_elms_Y) + x1
y = (y2-y1)*(j/N_elms_Y) + y1
z = (z2-z1)*(j/N_elms_Y) + z1
nodes.append([x,y,z,NID])
return nodes
if __name__ == '__main__':
main()