Last active
May 16, 2016 20:30
-
-
Save nicoguaro/ec588f3b135f31e2eb88 to your computer and use it in GitHub Desktop.
Scripts for automation of FreeCAD entities.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import division | |
import FreeCAD as FC | |
import Part | |
import numpy as np | |
def gen_fibers(nlines, nlayers, radius, hor_gap, vert_gap, theta, length): | |
"""Generate fibers forming the Herringbone pattern | |
Parameters | |
---------- | |
nlines : int | |
Number of curves per layer. | |
nlayers : int | |
Number of layers. | |
hor_gap : float (positive) | |
Horizontal gap between fibers. | |
vert_gap : float (positive) | |
Vertical gap between fibers/layers. | |
theta : float | |
Angle (in degrees) between consecutive layers. | |
length : float (positive) | |
Length of the fibers in the un-rotated/un-deformed | |
configuration. | |
Returns | |
------- | |
fibers : FreeCAD Fuse instance | |
Part with the fibers forming the Bouligand pattern. | |
""" | |
cyl = Part.makeCylinder(length/2, 60) | |
cyl.translate(FC.Vector(0, 0, -radius)) | |
cyl2 = cyl | |
y_vec = np.arange(-length/2, length/2, hor_gap) | |
z_vec = np.arange(0, vert_gap*nlayers, vert_gap) | |
fiber_list = [] | |
for cont_z, z in enumerate(z_vec): | |
angle = theta*cont_z | |
for y in y_vec: | |
fiber = Part.makeCylinder(radius, 1.04*length) | |
fiber.translate(FC.Vector(0, 0, -1.04*length/2)) | |
fiber.rotate(FC.Vector(0, 0, 0), | |
FC.Vector(0, 1, 0), 90) | |
fiber.translate(FC.Vector(0, y, z)) | |
fiber.rotate(FC.Vector(0, 0, 0), | |
FC.Vector(0, 0, 1), angle) | |
fiber_list.append(fiber.common(cyl)) | |
cyl2 = cyl2.cut(fiber) | |
bouligand = Part.makeCompound(fiber_list) | |
return bouligand, cyl2 | |
if __name__ == "__main__": | |
print("="*5 + "Bouligand example" + "="*5) | |
doc = FC.newDocument("bouligand_fine") | |
length = 60 | |
radius = 0.3 | |
vert_gap = 1.2 | |
nlines = 48 | |
hor_gap = length/nlines | |
nlayers = 37 | |
theta = 180/10 | |
fibers, cyl = gen_fibers(nlines, nlayers, radius, hor_gap, vert_gap, | |
theta, length) | |
Part.show(fibers) | |
Part.show(cyl) | |
print("Successful example!!") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
BSpline definition in FreeCAD | |
Every points is part of a list of FreeCAD.Vector class. | |
The example uses a hypotrochoid | |
https://en.wikipedia.org/wiki/Hypotrochoid | |
""" | |
import FreeCAD as FC | |
from FreeCAD import Base | |
import Draft | |
import numpy as np | |
from numpy import sin, cos, pi | |
def param_curve(t, R, r, d): | |
"""Coordinates of a hypotrochoid for parameters t, R, r and d""" | |
x = (R - r)*cos(t) + d*cos((R - r)/r*t) | |
y = (R - r)*sin(t) - d*sin((R - r)/r*t) | |
z = 3*sin(t) | |
return x, y, z | |
#%% | |
## Hypotrochoid | |
npts = 200 | |
R = 5. | |
r = 3. | |
d = 5. | |
t = np.linspace(0, 6*pi, npts) | |
x_vec, y_vec, z_vec = param_curve(t, R, r, d) | |
pts = [FC.Vector(x_vec[k], y_vec[k], z_vec[k]) for k in range(npts)] | |
path = Draft.makeBSpline(pts, closed=True, support=None) | |
## Circle perpendicular to the parametric curve | |
rad = 0.5 | |
vec = pts[1] - pts[0] | |
ang = vec.getAngle(FC.Vector(vec.x, vec.y, 0))*np.sign(vec.z) | |
ang = ang + pi/2 | |
axis = vec.cross(FC.Vector(vec.x, vec.y, 0)) | |
place = FC.Placement() | |
# Quaternion in FreeCAD | |
# q1 = sin(angle/2)*axis_1 | |
# q2 = sin(angle/2)*axis_2 | |
# q3 = sin(angle/2)*axis_3 | |
# q4 = cos(angle/2) | |
place.Rotation = (sin(ang/2)*axis[0], | |
sin(ang/2)*axis[1], | |
sin(ang/2)*axis[2], | |
cos(ang/2)) | |
place.Base = pts[0] | |
circle = Draft.makeCircle(radius=rad, placement=place) | |
## Sweep | |
doc = App.ActiveDocument | |
tube = doc.addObject('Part::Sweep','Sweep') | |
tube.Sections = circle | |
tube.Spine = path | |
tube.Solid = True | |
tube.Frenet = False | |
doc.recompute() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import division | |
import FreeCAD as FC | |
import Draft | |
import Part | |
import Mesh | |
import numpy as np | |
from numpy import array, sin, cos, pi | |
def surf_fun(x, y, z, amp, kx=1, ky=1): | |
r"""Eggshell-like function | |
.. math:: | |
f = A\sin(k_x \pi x) \sin(k_y \pi y) \enspace . | |
Parameters | |
---------- | |
x : array_like | |
x coordinate. | |
y : array_like | |
y coordinate. | |
z : array_like | |
z coordinate, vertical offset of the function. | |
kx : float (optional) | |
Spatial (semi)-frequency in `x`. | |
ky : float (optional) | |
Spatial (semi)-frequency in `y`. | |
Returns | |
------- | |
f : array_like | |
Function value `f(x, y, z)`. | |
""" | |
f = amp*sin(kx*pi*x)*sin(ky*pi*y) + z | |
return f | |
def create_curve_data(x_vec, y, z, theta, amp, kx=1, ky=1): | |
"""Points to generate the curve in space | |
The points form the curve generated from the intersection | |
between the function and a plane forming an angle theta | |
with respect to the plane xz. | |
Parameters | |
---------- | |
x_vec : array_like | |
Values for x in the un-rotated frame. | |
y : float | |
Value for y in the un-rotated frame. | |
z : float | |
Value for z in the current layer. | |
theta : float | |
Angle with respect to x (in radians). | |
amp : float | |
Amplitude of the function. | |
Returns | |
------- | |
pts : array_like | |
Function evaluated along the rotated line. | |
""" | |
xnew = np.cos(theta)*x_vec - np.sin(theta)*y | |
ynew = np.cos(theta)*y + np.sin(theta)*x_vec | |
znew = surf_fun(xnew, ynew, z, amp, kx=kx, ky=ky) | |
npts = len(xnew) | |
pts = [FC.Vector(xnew[k], ynew[k], znew[k]) | |
for k in range(npts)] | |
return pts | |
def make_circle(radius, theta, pts): | |
"""Circle perpendicular to the curve defined by a point list | |
Parameters | |
---------- | |
radius : float (positive) | |
Radius of the circle. | |
theta : float | |
Angle with respect to x (in radians). | |
pts : array | |
Point list that defines the curve in the space. | |
Returns | |
------- | |
circle : FreeCAD circle instance | |
Circle to be swept. | |
""" | |
vec = pts[1] - pts[0] | |
ang = vec.getAngle(FC.Vector(cos(theta), sin(theta), 0))*np.sign(vec.z) | |
ang = ang + pi/2 | |
axis = array([sin(theta), -cos(theta), 0]) | |
place = FC.Placement() | |
# Quaternion in FreeCAD | |
# q1 = sin(angle/2)*axis_1 | |
# q2 = sin(angle/2)*axis_2 | |
# q3 = sin(angle/2)*axis_3 | |
# q4 = cos(angle/2) | |
place.Rotation = (sin(ang/2)*axis[0], | |
sin(ang/2)*axis[1], | |
sin(ang/2)*axis[2], | |
cos(ang/2)) | |
place.Base = pts[0] | |
circle = Draft.makeCircle(radius=radius, placement=place) | |
return circle | |
def gen_fibers(npts, nlines, nlayers, amp, radius, hor_gap, vert_gap, theta, | |
length, kx=1, ky=1): | |
"""Generate fibers forming the Herringbone pattern | |
Parameters | |
---------- | |
npts : int | |
Number of points along each curve. | |
nlines : int | |
Number of curves per layer. | |
nlayers : int | |
Number of layers. | |
amp : float | |
Amplitude of the function. | |
hor_gap : float (positive) | |
Horizontal gap between fibers. | |
vert_gap : float (positive) | |
Vertical gap between fibers/layers. | |
theta : float | |
Angle (in radians) between consecutive layers. | |
length : float (positive) | |
Length of the fibers in the un-rotated/un-deformed | |
configuration. | |
Returns | |
------- | |
fibers : FreeCAD Fuse instance | |
Part with the fibers forming the Herringbone pattern. | |
""" | |
doc = FC.ActiveDocument | |
path_group = doc.addObject("App::DocumentObjectGroup","Paths") | |
circ_group = doc.addObject("App::DocumentObjectGroup","Circles") | |
fiber_group = doc.addObject("App::DocumentObjectGroup","Fibers") | |
x_vec = np.linspace(-length/2, length/2, npts) | |
y_vec = np.arange(-length/2, length/2, hor_gap) | |
z_vec = np.arange(0, vert_gap*nlayers, vert_gap) | |
fiber_list = [] | |
for cont_z, z in enumerate(z_vec): | |
angle = theta*cont_z | |
for cont_y, y in enumerate(y_vec): | |
pts = create_curve_data(x_vec, y, z, angle, amp, kx=kx, ky=ky) | |
rms = np.mean([(z - pt.z)**2 for pt in pts]) | |
if rms <= amp*1e-6: | |
curve = Draft.makeBSpline([pts[0], pts[-1]], closed=False, | |
support=None) | |
else: | |
curve = Draft.makeBSpline(pts, closed=False, support=None) | |
circle = make_circle(radius, angle, pts) | |
fiber = doc.addObject('Part::Sweep','Fiber') | |
fiber.Sections = [circle] | |
fiber.Spine = (curve) | |
fiber.Solid = True | |
fiber.Frenet = False | |
fiber_list.append(fiber) | |
# Add features to groups | |
fiber_group.addObject(fiber) | |
path_group.addObject(curve) | |
circ_group.addObject(circle) | |
herring = doc.addObject("Part::Compound","Compound") | |
herring.Links = fiber_list | |
return herring | |
if __name__ == "__main__": | |
print("="*5 + "Herringbone example" + "="*5) | |
doc = FC.newDocument("herring_fine") | |
npts = 41 | |
length = 60 | |
amp = 3.0 | |
radius = 0.3 | |
vert_gap = 1.2 | |
nlines = 48 | |
hor_gap = length/nlines | |
nlayers = 40 | |
theta = pi/10 | |
herring = gen_fibers(npts, nlines, nlayers, amp, radius, hor_gap, vert_gap, | |
theta, length, kx=0.1, ky=0.1) | |
doc.recompute() | |
# Save file | |
fname = "D:/workspace/vol_printing/examples/herrring_fine.FCStd" | |
doc.saveAs(fname) | |
print("Successful example!!") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import division | |
import FreeCAD as FC | |
import Part | |
import numpy as np | |
object_name = "Shape" | |
vol = FC.ActiveDocument.getObject(object_name).Shape.Volume | |
print(np.round(vol,4)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment