Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions freecad/gridfinity_workbench/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
STACKING_LIP_TOP_LEDGE = 0.4
STACKING_LIP_BOTTOM_CHAMFER = 0.7
STACKING_LIP_VERTICAL_SECTION = 1.8
STACKING_LIP_NOTCHES = False
STACKING_LIP_NOTCHES_CHAMFER = 0.6
STACKING_LIP_NOTCHES_RECESS = 0.6

RECESSED_TOP_DEPTH = 0
SEQUENTIAL_BRIDGING_LAYER_HEIGHT = 0.2
Expand Down
187 changes: 186 additions & 1 deletion freecad/gridfinity_workbench/feature_construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -1210,12 +1210,100 @@ def _stacking_lip_profile(obj: fc.DocumentObject) -> Part.Wire:
fc.Vector(x5, y, -abs(x5.Value - x3.Value)), # 45 degree chamfer under the lip
fc.Vector(x1, y, -abs(x5.Value - x3.Value)),
]
if obj.StackingLipNotches:
st = [
fc.Vector(x1, y, 0),
fc.Vector(x4, y, 0),
fc.Vector(x4, y, z4),
fc.Vector(x5, y, z5),
fc.Vector(x1, y, z5),
]
else:
st = [
fc.Vector(x1, y, 0),
fc.Vector(x1, y, z1),
fc.Vector(x2, y, z1),
fc.Vector(x3, y, z2),
fc.Vector(x3, y, z3),
fc.Vector(x4, y, 0),
fc.Vector(x4, y, z4),
fc.Vector(x5, y, z5),
fc.Vector(x5, y, 0),
]

stacking_lip_profile = Part.Wire(Part.Shape(utils.loop(st)).Edges)

return stacking_lip_profile


def _stacking_lip_plate(
obj: fc.DocumentObject,
layout: GridfinityLayout,
) -> Part.Shape:
"""Creaet complex shaped bin base."""
x_bt_cmf_width = (
(obj.xGridSize - obj.Clearance * 2)
- 2 * obj.StackingLipBottomChamfer
- 2 * obj.StackingLipTopChamfer
- 2 * obj.StackingLipTopLedge
)
y_bt_cmf_width = (
(obj.yGridSize - obj.Clearance * 2)
- 2 * obj.StackingLipBottomChamfer
- 2 * obj.StackingLipTopChamfer
- 2 * obj.StackingLipTopLedge
)
x_vert_width = (
(obj.xGridSize - obj.Clearance * 2)
- 2 * obj.StackingLipTopChamfer
- 2 * obj.StackingLipTopLedge
)
y_vert_width = (
(obj.yGridSize - obj.Clearance * 2)
- 2 * obj.StackingLipTopChamfer
- 2 * obj.StackingLipTopLedge
)

bottom_chamfer = utils.rounded_rectangle_chamfer(
x_bt_cmf_width,
y_bt_cmf_width,
zeromm,
obj.StackingLipBottomChamfer,
obj.BinOuterRadius
- obj.StackingLipTopLedge
- obj.StackingLipTopChamfer
- obj.StackingLipBottomChamfer,
)

vertical_section = utils.rounded_rectangle_extrude(
x_vert_width,
y_vert_width,
obj.StackingLipBottomChamfer,
obj.StackingLipVerticalSection,
obj.BinOuterRadius - obj.StackingLipTopLedge - obj.StackingLipTopChamfer,
)
assembly = bottom_chamfer.fuse(vertical_section)

top_chamfer = utils.rounded_rectangle_chamfer(
x_vert_width,
y_vert_width,
obj.StackingLipBottomChamfer + obj.StackingLipVerticalSection,
obj.StackingLipTopChamfer,
obj.BinOuterRadius - obj.StackingLipTopLedge - obj.StackingLipTopChamfer,
)

assembly = bottom_chamfer.multiFuse([vertical_section, top_chamfer])

fuse_total = utils.copy_in_layout(assembly, layout, obj.xGridSize, obj.yGridSize)

return fuse_total.translate(
fc.Vector(
obj.xGridSize / 2,
obj.yGridSize / 2,
),
)


def stacking_lip_properties(
obj: fc.DocumentObject,
*,
Expand Down Expand Up @@ -1277,18 +1365,115 @@ def stacking_lip_properties(
read_only=True,
).StackingLipVerticalSection = const.STACKING_LIP_VERTICAL_SECTION

## Gridfinity Non Standard Parameters
obj.addProperty(
"App::PropertyBool",
"StackingLipNotches",
"GridfinityNonStandard",
"Toggle the notches on the stacking lip on or off",
).StackingLipNotches = const.STACKING_LIP_NOTCHES
obj.addProperty(
"App::PropertyLength",
"StackingLipNotchesChamfer",
"GridfinityNonStandard",
"Chamfer on the notches of the Stacking lip<br>"
f" <br> 0 to disable<br> <br> default = {const.STACKING_LIP_NOTCHES_CHAMFER} mm ",
).StackingLipNotchesChamfer = const.STACKING_LIP_NOTCHES_CHAMFER
obj.addProperty(
"App::PropertyLength",
"StackingLipNotchesRecess",
"GridfinityNonStandard",
"Recess of the notches of the Stacking lip<br>"
f" <br> 0 to disable<br> <br> default = {const.STACKING_LIP_NOTCHES_RECESS} mm ",
).StackingLipNotchesRecess = const.STACKING_LIP_NOTCHES_RECESS

def make_stacking_lip(obj: fc.DocumentObject, bin_outside_shape: Part.Wire) -> Part.Shape:
def make_stacking_lip(obj: fc.DocumentObject, layout: GridfinityLayout, bin_outside_shape: Part.Wire) -> Part.Shape:
"""Create stacking lip based on input bin shape.

Args:
obj (FreeCAD.DocumentObject): DocumentObject
layout (GridfinityLayout): layout of the bin
bin_outside_shape (Part.Wire): exterior wall of the bin

"""
wire = _stacking_lip_profile(obj)
stacking_lip = Part.Wire(bin_outside_shape).makePipe(wire)
stacking_lip = Part.makeSolid(stacking_lip)
if obj.StackingLipNotches:
height = (
obj.StackingLipBottomChamfer
+ obj.StackingLipVerticalSection
+ obj.StackingLipTopChamfer
)
cover = utils.rounded_rectangle_extrude(
obj.xTotalWidth,
obj.yTotalWidth,
0,
height,
obj.BinOuterRadius,
).translate(
fc.Vector(
obj.xTotalWidth / 2 + obj.Clearance,
obj.yTotalWidth / 2 + obj.Clearance,
),
)
base = _stacking_lip_plate(obj, layout)
cover = cover.cut(base)
offset = obj.StackingLipTopLedge + obj.StackingLipTopChamfer + obj.StackingLipBottomChamfer
cutout = utils.rounded_rectangle_extrude(
obj.xTotalWidth - offset * 2,
obj.yTotalWidth - offset * 2,
0,
height,
obj.BinOuterRadius - offset,
).translate(
fc.Vector(
obj.xTotalWidth / 2 + obj.Clearance,
obj.yTotalWidth / 2 + obj.Clearance,
),
)

if obj.StackingLipNotchesRecess > 0:
chamfer_offset = obj.StackingLipTopLedge + obj.StackingLipNotchesRecess
cutout_recess = utils.rounded_rectangle_chamfer(
obj.xTotalWidth - chamfer_offset * 2,
obj.yTotalWidth - chamfer_offset * 2,
height - obj.StackingLipNotchesRecess,
obj.StackingLipNotchesRecess,
obj.BinOuterRadius - obj.StackingLipTopLedge - obj.StackingLipNotchesRecess,
).translate(
fc.Vector(
obj.xTotalWidth / 2 + obj.Clearance,
obj.yTotalWidth / 2 + obj.Clearance,
),
)
cutout = cutout.fuse(cutout_recess)

if obj.StackingLipNotchesChamfer > 0:
chamfer_offset = (
obj.StackingLipTopLedge + obj.StackingLipTopChamfer + obj.StackingLipBottomChamfer
)
cutout_chamfer = utils.rounded_rectangle_chamfer(
obj.xTotalWidth - chamfer_offset * 2,
obj.yTotalWidth - chamfer_offset * 2,
height - obj.StackingLipNotchesRecess - obj.StackingLipNotchesChamfer,
obj.StackingLipNotchesChamfer,
obj.BinOuterRadius
- obj.StackingLipTopLedge
- obj.StackingLipNotchesRecess
- obj.StackingLipNotchesChamfer,
).translate(
fc.Vector(
obj.xTotalWidth / 2 + obj.Clearance,
obj.yTotalWidth / 2 + obj.Clearance,
),
)
cutout = cutout.fuse(cutout_chamfer)

cover = cover.cut(cutout)
stacking_lip = stacking_lip.fuse(cover)
stacking_lip = stacking_lip.removeSplitter()

stacking_lip = stacking_lip.translate(
fc.Vector(-obj.xLocationOffset, -obj.yLocationOffset),
)
Expand Down
57 changes: 54 additions & 3 deletions freecad/gridfinity_workbench/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,59 @@ def __init__(self, obj: fc.DocumentObject) -> None:

obj.Proxy = self

def add_property_if_missing( # noqa: PLR0913
self,
obj: fc.DocumentObject,
default_value: object,
prop_type: str,
name: str,
group: str = "",
doc: str = "",
attr: int = 0,
read_only: bool = False, # noqa: FBT001, FBT002
hidden: bool = False, # noqa: FBT001, FBT002
) -> None:
if name not in obj.PropertiesList:
obj = obj.addProperty(
type=prop_type,
name=name,
group=group,
doc=doc,
attr=attr,
read_only=read_only,
hidden=hidden,
)
setattr(obj, name, default_value)

def onDocumentRestored(self, obj: fc.DocumentObject) -> None: # noqa: N802
check_version.migrate_object_version(obj)
if hasattr(obj, "StackingLip"):
self.add_property_if_missing(
obj,
const.STACKING_LIP_NOTCHES,
"App::PropertyBool",
"StackingLipNotches",
"GridfinityNonStandard",
"Toggle the notches on the stacking lip on or off",
)
self.add_property_if_missing(
obj,
const.STACKING_LIP_NOTCHES_CHAMFER,
"App::PropertyLength",
"StackingLipNotchesChamfer",
"GridfinityNonStandard",
"Chamfer on the notches of the Stacking lip<br>"
f" <br> 0 to disable<br> <br> default = {const.STACKING_LIP_NOTCHES_CHAMFER} mm ",
)
self.add_property_if_missing(
obj,
const.STACKING_LIP_NOTCHES_RECESS,
"App::PropertyLength",
"StackingLipNotchesRecess",
"GridfinityNonStandard",
"Recess of the notches of the Stacking lip<br> "
f"<br> 0 to disable<br> <br> default = {const.STACKING_LIP_NOTCHES_RECESS} mm ",
)

def execute(self, fp: Part.Feature) -> None:
gridfinity_shape = self.generate_gridfinity_shape(fp)
Expand Down Expand Up @@ -128,7 +179,7 @@ def generate_gridfinity_shape(self, obj: fc.DocumentObject) -> Part.Shape:
fuse_total = fuse_total.cut(feat.make_blank_bin_recessed_top(obj, bin_inside_shape))

if obj.StackingLip:
fuse_total = fuse_total.fuse(feat.make_stacking_lip(obj, bin_outside_shape))
fuse_total = fuse_total.fuse(feat.make_stacking_lip(obj, layout, bin_outside_shape))

if obj.ScrewHoles or obj.MagnetHoles:
fuse_total = fuse_total.cut(feat.make_bin_bottom_holes(obj, layout))
Expand Down Expand Up @@ -220,7 +271,7 @@ def generate_gridfinity_shape(self, obj: fc.DocumentObject) -> Part.Shape:
fuse_total = fuse_total.cut(feat.make_compartments(obj, compartments))

if obj.StackingLip:
fuse_total = fuse_total.fuse(feat.make_stacking_lip(obj, bin_outside_shape))
fuse_total = fuse_total.fuse(feat.make_stacking_lip(obj, layout, bin_outside_shape))

if obj.ScrewHoles or obj.MagnetHoles:
fuse_total = fuse_total.cut(feat.make_bin_bottom_holes(obj, layout))
Expand Down Expand Up @@ -327,7 +378,7 @@ def generate_gridfinity_shape(self, obj: fc.DocumentObject) -> Part.Shape:
fuse_total = fuse_total.cut(feat.make_bin_bottom_holes(obj, layout))

if obj.StackingLip:
fuse_total = fuse_total.fuse(feat.make_stacking_lip(obj, bin_outside_shape))
fuse_total = fuse_total.fuse(feat.make_stacking_lip(obj, layout, bin_outside_shape))

if obj.LabelShelfStyle != "Off":
fuse_total = fuse_total.fuse(feat.make_label_shelf(obj, "eco"))
Expand Down
3 changes: 2 additions & 1 deletion freecad/gridfinity_workbench/grid_initial_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import FreeCAD as fc # noqa: N813

from . import const
from .utils import GridfinityLayout


def _location_properties(obj: fc.DocumentObject) -> None:
Expand Down Expand Up @@ -154,7 +155,7 @@ def custom_shape_layout_properties(obj: fc.DocumentObject, *, baseplate_default:
hidden=True,
).Baseplate = baseplate_default


# def make_custom_shape_layout(obj: fc.DocumentObject, layout: GridfinityLayout) -> None:
def make_custom_shape_layout(obj: fc.DocumentObject, layout: list[list[bool]]) -> None:
"""Calculate values for custom shape.

Expand Down