![]() |
As a way to introduce our brass coins to the community, we will raffle off a free coin during the month of August. Follow link ABOVE for instructions for entering. |
![]() |
![]() |
The beloved Ships in Scale Magazine is back and charting a new course for 2026! Discover new skills, new techniques, and new inspirations in every issue. NOTE THAT OUR NEXT ISSUE WILL BE MARCH/APRIL 2026 |
![]() |








import FreeCAD, Part
import numpy as np
doc = FreeCAD.ActiveDocument
# -------------------------------------------------------
# Variables
# -------------------------------------------------------
X_positions = [0.0, 2.78, 5.56, 8.33, 11.11, 13.89, 16.67, 19.44, 22.22, 25.0]
num_points_vertical = 20
num_points_horizontal = 40
Z_plane = -3
horizontal_profiles = [
[(0,0,0), (12.5,0,0), (25,0,0)],
[(0,-6,0.5), (12.5,-6,2), (25,-6,0.5)],
[(0,-10,-2), (12.5,-9,1), (25,-10,-2)]
]
# -------------------------------------------------------
# Helpfunction paraboles
# -------------------------------------------------------
def parabola_3points(x_pts, y_pts):
A = np.array([[x_pts[0]**2, x_pts[0],1],
[x_pts[1]**2, x_pts[1],1],
[x_pts[2]**2, x_pts[2],1]])
Y = np.array(y_pts)
return np.linalg.solve(A,Y)
# -------------------------------------------------------
# Calculate paraboles
# -------------------------------------------------------
top_a, top_b, top_c = parabola_3points(
[p[0] for p in horizontal_profiles[0]],
[p[2] for p in horizontal_profiles[0]]
)
mid_a, mid_b, mid_c = parabola_3points(
[p[0] for p in horizontal_profiles[1]],
[p[2] for p in horizontal_profiles[1]]
)
bot_a_z, bot_b_z, bot_c_z = parabola_3points(
[p[0] for p in horizontal_profiles[2]],
[p[2] for p in horizontal_profiles[2]]
)
bot_a_y, bot_b_y, bot_c_y = parabola_3points(
[p[0] for p in horizontal_profiles[2]],
[p[1] for p in horizontal_profiles[2]]
)
# -------------------------------------------------------
# Vertical splines
# -------------------------------------------------------
vertical_splines = []
for X in X_positions:
Z_top = top_a*X**2 + top_b*X + top_c
Z_mid = mid_a*X**2 + mid_b*X + mid_c
Z_bot = bot_a_z*X**2 + bot_b_z*X + bot_c_z
Y_top = horizontal_profiles[0][0][1]
Y_mid = horizontal_profiles[1][0][1]
Y_bot = bot_a_y*X**2 + bot_b_y*X + bot_c_y
A = np.array([[Y_top**2, Y_top,1],
[Y_mid**2, Y_mid,1],
[Y_bot**2, Y_bot,1]])
Z_vec = np.array([Z_top, Z_mid, Z_bot])
a_v, b_v, c_v = np.linalg.solve(A, Z_vec)
Y_sample = np.linspace(Y_top, Y_bot, num_points_vertical)
pts = []
for Y in Y_sample:
Z = a_v*Y**2 + b_v*Y + c_v
pts.append(FreeCAD.Vector(X,Y,Z))
spline = Part.BSplineCurve()
spline.interpolate(pts)
edge = spline.toShape()
vertical_splines.append(edge)
Part.show(edge)
# -------------------------------------------------------
# Upper spline
# -------------------------------------------------------
top_pts = []
for X in np.linspace(0,25,num_points_horizontal):
Z = top_a*X**2 + top_b*X + top_c
Y = horizontal_profiles[0][0][1]
top_pts.append(FreeCAD.Vector(X,Y,Z))
top_edge = Part.BSplineCurve()
top_edge.interpolate(top_pts)
top_edge = top_edge.toShape()
Part.show(top_edge)
# -------------------------------------------------------
# Lower spline
# -------------------------------------------------------
bottom_pts = []
for X in np.linspace(0,25,num_points_horizontal):
Y = bot_a_y*X**2 + bot_b_y*X + bot_c_y
Z = bot_a_z*X**2 + bot_b_z*X + bot_c_z
bottom_pts.append(FreeCAD.Vector(X,Y,Z))
bottom_edge = Part.BSplineCurve()
bottom_edge.interpolate(bottom_pts)
bottom_edge = bottom_edge.toShape()
Part.show(bottom_edge)
doc.recompute()
# -------------------------------------------------------
# Show length
# -------------------------------------------------------
print("Spline 1 lengte :", vertical_splines[0].Length)
print("Spline 5 lengte :", vertical_splines[4].Length)
# -------------------------------------------------------
# Determine corners
# -------------------------------------------------------
left_top = vertical_splines[0].Vertexes[0].Point
right_top = vertical_splines[-1].Vertexes[0].Point
right_bottom = vertical_splines[-1].Vertexes[-1].Point
left_bottom = vertical_splines[0].Vertexes[-1].Point
corner_points = [left_top, right_top, right_bottom, left_bottom]
# -------------------------------------------------------
# Extra spline between original lower corners
# -------------------------------------------------------
extra_bottom_spline = Part.BSplineCurve()
extra_bottom_spline.interpolate([left_bottom, right_bottom])
Part.show(extra_bottom_spline.toShape())
# -------------------------------------------------------
# Perpendicular splines to Z=-3
# -------------------------------------------------------
bottom_plane_points = []
for pt in corner_points:
target = FreeCAD.Vector(pt.x, pt.y, Z_plane)
spline = Part.BSplineCurve()
spline.interpolate([pt, target])
Part.show(spline.toShape())
bottom_plane_points.append(target)
# -------------------------------------------------------
# Splines in Z=-3
# -------------------------------------------------------
for i in range(4):
p1 = bottom_plane_points[i]
p2 = bottom_plane_points[(i+1)%4]
spline = Part.BSplineCurve()
spline.interpolate([p1, p2])
Part.show(spline.toShape())
doc.recompute()
print("Script execution is ready.")

