From 5c161c8c66e3a556870bdc993b1c636f52451ace Mon Sep 17 00:00:00 2001 From: Chris Kinsman Date: Wed, 4 Feb 2026 16:18:23 -0800 Subject: [PATCH] Add side padding for Bins (#1) * Update UI to collect padding information * Padding on Left and Top working * Left and Bottom Padding working * Fix top clearance origin * Fix base clearance cutout to use padding * Fix padding with lip * Update label --- commands/commandCreateBaseplate/entry.py | 2 +- commands/commandCreateBin/entry.py | 71 ++++++++++++++++++- lib/gridfinityUtils/baseGenerator.py | 18 +++-- lib/gridfinityUtils/baseGeneratorInput.py | 47 +++++++++++- .../baseplateGeneratorInput.py | 8 +-- lib/gridfinityUtils/binBodyGenerator.py | 34 +++++---- lib/gridfinityUtils/binBodyGeneratorInput.py | 46 ++++++++++++ lib/gridfinityUtils/binBodyLipGenerator.py | 14 ++-- .../binBodyLipGeneratorInput.py | 47 +++++++++++- 9 files changed, 253 insertions(+), 34 deletions(-) diff --git a/commands/commandCreateBaseplate/entry.py b/commands/commandCreateBaseplate/entry.py index 0a42f1f..dda62d1 100644 --- a/commands/commandCreateBaseplate/entry.py +++ b/commands/commandCreateBaseplate/entry.py @@ -254,7 +254,7 @@ def command_created(args: adsk.core.CommandCreatedEventArgs): sidePaddingGroup = plateFeaturesGroup.children.addGroupCommandInput(SIDE_PADDING_GROUP, 'Side padding') sidePaddingGroup.isExpanded = uiState.getState(SIDE_PADDING_GROUP) uiState.registerCommandInput(sidePaddingGroup) - generateSidePaddingInput = sidePaddingGroup.children.addBoolValueInput(BASEPLATE_WITH_SIDE_PADDING_INPUT, 'Add side padding', True, '', uiState.getState(BASEPLATE_WITH_SIDE_PADDING_INPUT)) + generateSidePaddingInput = sidePaddingGroup.children.addBoolValueInput(BASEPLATE_WITH_SIDE_PADDING_INPUT, 'Add padding', True, '', uiState.getState(BASEPLATE_WITH_SIDE_PADDING_INPUT)) uiState.registerCommandInput(generateSidePaddingInput) sidePaddingLeftInput = sidePaddingGroup.children.addValueInput(BASEPLATE_SIDE_PADDING_LEFT_INPUT, 'Padding left', defaultLengthUnits, adsk.core.ValueInput.createByReal(uiState.getState(BASEPLATE_SIDE_PADDING_LEFT_INPUT))) diff --git a/commands/commandCreateBin/entry.py b/commands/commandCreateBin/entry.py index 3568d35..186d623 100644 --- a/commands/commandCreateBin/entry.py +++ b/commands/commandCreateBin/entry.py @@ -64,6 +64,7 @@ BIN_SCOOP_GROUP_ID = 'bin_scoop_group' BIN_TAB_FEATURES_GROUP_ID = 'bin_tab_features_group' BIN_BASE_FEATURES_GROUP_ID = 'bin_base_features_group' +BIN_PADDING_GROUP_ID = 'bin_padding_group' USER_CHANGES_GROUP_ID = 'user_changes_group' PREVIEW_GROUP_ID = 'preview_group' INFO_GROUP = 'info_group' @@ -117,6 +118,11 @@ BIN_TYPE_HOLLOW = 'Hollow' BIN_TYPE_SHELLED = 'Shelled' BIN_TYPE_SOLID = 'Solid' +BIN_HAS_PADDING_INPUT_ID = 'bin_has_padding' +BIN_PADDING_LEFT_INPUT_ID = 'bin_padding_left' +BIN_PADDING_TOP_INPUT_ID = 'bin_padding_top' +BIN_PADDING_RIGHT_INPUT_ID = 'bin_padding_right' +BIN_PADDING_BOTTOM_INPUT_ID = 'bin_padding_bottom' INPUT_CHANGES_SAVE_DEFAULTS = 'input_changes_buttons_save_new_defaults' INPUT_CHANGES_RESET_TO_DEFAULTS = 'input_changes_button_reset_to_defaults' @@ -152,6 +158,7 @@ def initDefaultUiState(): commandUIState.initValue(BIN_SCOOP_GROUP_ID, True, adsk.core.GroupCommandInput.classType()) commandUIState.initValue(BIN_TAB_FEATURES_GROUP_ID, True, adsk.core.GroupCommandInput.classType()) commandUIState.initValue(BIN_BASE_FEATURES_GROUP_ID, True, adsk.core.GroupCommandInput.classType()) + commandUIState.initValue(BIN_PADDING_GROUP_ID, True, adsk.core.GroupCommandInput.classType()) commandUIState.initValue(USER_CHANGES_GROUP_ID, True, adsk.core.GroupCommandInput.classType()) commandUIState.initValue(PREVIEW_GROUP_ID, True, adsk.core.GroupCommandInput.classType()) @@ -191,6 +198,12 @@ def initDefaultUiState(): commandUIState.initValue(BIN_MAGNET_DIAMETER_INPUT, const.DIMENSION_MAGNET_CUTOUT_DIAMETER, adsk.core.ValueCommandInput.classType()) commandUIState.initValue(BIN_MAGNET_HEIGHT_INPUT, const.DIMENSION_MAGNET_CUTOUT_DEPTH, adsk.core.ValueCommandInput.classType()) + commandUIState.initValue(BIN_HAS_PADDING_INPUT_ID, False, adsk.core.BoolValueCommandInput.classType()) + commandUIState.initValue(BIN_PADDING_LEFT_INPUT_ID, 0, adsk.core.ValueCommandInput.classType()) + commandUIState.initValue(BIN_PADDING_TOP_INPUT_ID, 0, adsk.core.ValueCommandInput.classType()) + commandUIState.initValue(BIN_PADDING_RIGHT_INPUT_ID, 0, adsk.core.ValueCommandInput.classType()) + commandUIState.initValue(BIN_PADDING_BOTTOM_INPUT_ID, 0, adsk.core.ValueCommandInput.classType()) + commandCompartmentsTableUIState = [] recordedDefaults = configUtils.readJsonConfig(UI_INPUT_DEFAULTS_CONFIG_PATH) if recordedDefaults is not None and 'static_ui' in recordedDefaults and 'compartments_table' in recordedDefaults: @@ -331,15 +344,19 @@ def update_actual_compartment_unit_dimensions(): baseLength: float = commandUIState.getState(BIN_BASE_LENGTH_UNIT_INPUT_ID) binWidth: float = commandUIState.getState(BIN_WIDTH_INPUT_ID) binLength: float = commandUIState.getState(BIN_LENGTH_INPUT_ID) + binPaddingLeft: float = commandUIState.getState(BIN_PADDING_LEFT_INPUT_ID) if commandUIState.getState(BIN_HAS_PADDING_INPUT_ID) else 0 + binPaddingTop: float = commandUIState.getState(BIN_PADDING_TOP_INPUT_ID) if commandUIState.getState(BIN_HAS_PADDING_INPUT_ID) else 0 + binPaddingRight: float = commandUIState.getState(BIN_PADDING_RIGHT_INPUT_ID) if commandUIState.getState(BIN_HAS_PADDING_INPUT_ID) else 0 + binPaddingBottom: float = commandUIState.getState(BIN_PADDING_BOTTOM_INPUT_ID) if commandUIState.getState(BIN_HAS_PADDING_INPUT_ID) else 0 gridWidth: int = commandUIState.getState(BIN_COMPARTMENTS_GRID_BASE_WIDTH_ID) gridLength: int = commandUIState.getState(BIN_COMPARTMENTS_GRID_BASE_LENGTH_ID) wallThickness: float = commandUIState.getState(BIN_WALL_THICKNESS_INPUT_ID) xyClearance: float = commandUIState.getState(BIN_WITH_LIP_INPUT_ID) try: minCompartmentDimensionLimit = (const.BIN_CORNER_FILLET_RADIUS - wallThickness) * 2 * 10 - cellWidth = round((baseWidth * binWidth - wallThickness * 2 - xyClearance * 2 - wallThickness * (gridWidth - 1)) / gridWidth * 10, 2) + cellWidth = round((baseWidth * binWidth + binPaddingLeft + binPaddingRight - wallThickness * 2 - xyClearance * 2 - wallThickness * (gridWidth - 1)) / gridWidth * 10, 2) actualCompartmentDimensionsUiState.updateValue(BIN_COMPARTMENT_REAL_DIMENSIONS_WIDTH, formatString(f'Grid cell width: {cellWidth}mm', '' if cellWidth >= minCompartmentDimensionLimit else 'red')) - cellLength = round((baseLength * binLength - wallThickness * 2 - xyClearance * 2 - wallThickness * (gridLength - 1)) / gridLength * 10, 2) + cellLength = round((baseLength * binLength + binPaddingTop + binPaddingBottom - wallThickness * 2 - xyClearance * 2 - wallThickness * (gridLength - 1)) / gridLength * 10, 2) actualCompartmentDimensionsUiState.updateValue(BIN_COMPARTMENT_REAL_DIMENSIONS_LENGTH, formatString(f'Grid cell length: {cellLength}mm', '' if cellLength >= minCompartmentDimensionLimit else 'red')) except: showErrorInMessageBox() @@ -349,7 +366,11 @@ def update_actual_bin_dimensions(): try: actualWidth = commandUIState.getState(BIN_BASE_WIDTH_UNIT_INPUT_ID) * commandUIState.getState(BIN_WIDTH_INPUT_ID) - const.BIN_XY_CLEARANCE * 2 actualLength = commandUIState.getState(BIN_BASE_LENGTH_UNIT_INPUT_ID) * commandUIState.getState(BIN_LENGTH_INPUT_ID) - const.BIN_XY_CLEARANCE * 2 - actualHeight = commandUIState.getState(BIN_HEIGHT_UNIT_INPUT_ID) * commandUIState.getState(BIN_HEIGHT_INPUT_ID) + ((const.BIN_LIP_EXTRA_HEIGHT - const.BIN_LIP_TOP_RECESS_HEIGHT) if commandUIState.getState(BIN_WITH_LIP_INPUT_ID) else 0) + actualHeight = commandUIState.getState(BIN_HEIGHT_UNIT_INPUT_ID) * commandUIState.getState(BIN_HEIGHT_INPUT_ID) + ((const.BIN_LIP_EXTRA_HEIGHT - const.BIN_LIP_TOP_RECESS_HEIGHT) if commandUIState.getState(BIN_WITH_LIP_INPUT_ID) else 0) + if commandUIState.getState(BIN_HAS_PADDING_INPUT_ID): + actualWidth += commandUIState.getState(BIN_PADDING_LEFT_INPUT_ID) + commandUIState.getState(BIN_PADDING_RIGHT_INPUT_ID) + actualLength += commandUIState.getState(BIN_PADDING_TOP_INPUT_ID) + commandUIState.getState(BIN_PADDING_BOTTOM_INPUT_ID) + totalWidthValue = round(actualWidth * 10, 2) totalLengthValue = round(actualLength * 10, 2) totalHeightValue = round(actualHeight * 10, 2) @@ -462,6 +483,11 @@ def is_all_input_valid(inputs: adsk.core.CommandInputs): binCompartmentsTable: adsk.core.TableCommandInput = inputs.itemById(BIN_COMPARTMENTS_TABLE_ID) compartmentsX: adsk.core.IntegerSpinnerCommandInput = inputs.itemById(BIN_COMPARTMENTS_GRID_BASE_WIDTH_ID) compartmentsY: adsk.core.IntegerSpinnerCommandInput = inputs.itemById(BIN_COMPARTMENTS_GRID_BASE_LENGTH_ID) + has_padding: adsk.core.BoolValueCommandInput = inputs.itemById(BIN_HAS_PADDING_INPUT_ID) + padding_left: adsk.core.ValueCommandInput = inputs.itemById(BIN_PADDING_LEFT_INPUT_ID) + padding_top: adsk.core.ValueCommandInput = inputs.itemById(BIN_PADDING_TOP_INPUT_ID) + padding_right: adsk.core.ValueCommandInput = inputs.itemById(BIN_PADDING_RIGHT_INPUT_ID) + padding_bottom: adsk.core.ValueCommandInput = inputs.itemById(BIN_PADDING_BOTTOM_INPUT_ID) result = result and base_width_unit.value > 1 result = result and base_length_unit.value > 1 @@ -654,6 +680,28 @@ def command_created(args: adsk.core.CommandCreatedEventArgs): magnetHeightInput.isMinimumInclusive = True commandUIState.registerCommandInput(magnetHeightInput) + paddingGroup = inputs.addGroupCommandInput(BIN_PADDING_GROUP_ID, 'Side padding') + paddingGroup.isExpanded = commandUIState.getState(BIN_PADDING_GROUP_ID) + commandUIState.registerCommandInput(paddingGroup) + hasPaddingCheckboxInput = paddingGroup.children.addBoolValueInput(BIN_HAS_PADDING_INPUT_ID, 'Add padding', True, '', commandUIState.getState(BIN_HAS_PADDING_INPUT_ID)) + commandUIState.registerCommandInput(hasPaddingCheckboxInput) + paddingLeftInput = paddingGroup.children.addValueInput(BIN_PADDING_LEFT_INPUT_ID, 'Padding left', defaultLengthUnits, adsk.core.ValueInput.createByReal(commandUIState.getState(BIN_PADDING_LEFT_INPUT_ID))) + paddingLeftInput.minimumValue = 0 + paddingLeftInput.isMinimumInclusive = True + commandUIState.registerCommandInput(paddingLeftInput) + paddingTopInput = paddingGroup.children.addValueInput(BIN_PADDING_TOP_INPUT_ID, 'Padding top', defaultLengthUnits, adsk.core.ValueInput.createByReal(commandUIState.getState(BIN_PADDING_TOP_INPUT_ID))) + paddingTopInput.minimumValue = 0 + paddingTopInput.isMinimumInclusive = True + commandUIState.registerCommandInput(paddingTopInput) + paddingRightInput = paddingGroup.children.addValueInput(BIN_PADDING_RIGHT_INPUT_ID, 'Padding right', defaultLengthUnits, adsk.core.ValueInput.createByReal(commandUIState.getState(BIN_PADDING_RIGHT_INPUT_ID))) + paddingRightInput.minimumValue = 0 + paddingRightInput.isMinimumInclusive = True + commandUIState.registerCommandInput(paddingRightInput) + paddingBottomInput = paddingGroup.children.addValueInput(BIN_PADDING_BOTTOM_INPUT_ID, 'Padding bottom', defaultLengthUnits, adsk.core.ValueInput.createByReal(commandUIState.getState(BIN_PADDING_BOTTOM_INPUT_ID))) + paddingBottomInput.minimumValue = 0 + paddingBottomInput.isMinimumInclusive = True + commandUIState.registerCommandInput(paddingBottomInput) + userChangesGroup = inputs.addGroupCommandInput(USER_CHANGES_GROUP_ID, 'Changes') userChangesGroup.isExpanded = commandUIState.getState(USER_CHANGES_GROUP_ID) commandUIState.registerCommandInput(userChangesGroup) @@ -882,6 +930,12 @@ def generateBin(args: adsk.core.CommandEventArgs): binCompartmentsTable: adsk.core.TableCommandInput = inputs.itemById(BIN_COMPARTMENTS_TABLE_ID) compartmentsX: adsk.core.IntegerSpinnerCommandInput = inputs.itemById(BIN_COMPARTMENTS_GRID_BASE_WIDTH_ID) compartmentsY: adsk.core.IntegerSpinnerCommandInput = inputs.itemById(BIN_COMPARTMENTS_GRID_BASE_LENGTH_ID) + bin_padding: adsk.core.BoolValueCommandInput = inputs.itemById(BIN_HAS_PADDING_INPUT_ID) + bin_padding_left: adsk.core.ValueCommandInput = inputs.itemById(BIN_PADDING_LEFT_INPUT_ID) + bin_padding_top: adsk.core.ValueCommandInput = inputs.itemById(BIN_PADDING_TOP_INPUT_ID) + bin_padding_right: adsk.core.ValueCommandInput = inputs.itemById(BIN_PADDING_RIGHT_INPUT_ID) + bin_padding_bottom: adsk.core.ValueCommandInput = inputs.itemById(BIN_PADDING_BOTTOM_INPUT_ID) + isHollow = binTypeDropdownInput.selectedItem.name == BIN_TYPE_HOLLOW isSolid = binTypeDropdownInput.selectedItem.name == BIN_TYPE_SOLID @@ -923,6 +977,12 @@ def generateBin(args: adsk.core.CommandEventArgs): baseGeneratorInput.screwHolesDiameter = bin_screw_hole_diameter.value baseGeneratorInput.magnetCutoutsDiameter = bin_magnet_cutout_diameter.value baseGeneratorInput.magnetCutoutsDepth = bin_magnet_cutout_depth.value + # Needed to calculate base clearance + baseGeneratorInput.hasPadding = bin_padding.value + baseGeneratorInput.paddingLeft = bin_padding_left.value + baseGeneratorInput.paddingTop = bin_padding_top.value + baseGeneratorInput.paddingRight = bin_padding_right.value + baseGeneratorInput.paddingBottom = bin_padding_bottom.value baseBodies: list[adsk.fusion.BRepBody] if bin_generate_base.value: @@ -956,6 +1016,11 @@ def generateBin(args: adsk.core.CommandEventArgs): binBodyInput.tabOverhangAngle = binTabAngle.value binBodyInput.compartmentsByX = compartmentsX.value binBodyInput.compartmentsByY = compartmentsY.value + binBodyInput.hasPadding = bin_padding.value + binBodyInput.paddingLeft = bin_padding_left.value + binBodyInput.paddingTop = bin_padding_top.value + binBodyInput.paddingRight = bin_padding_right.value + binBodyInput.paddingBottom = bin_padding_bottom.value if binCompartmentGridTypeDropdownInput.selectedItem.name == BIN_COMPARTMENTS_GRID_TYPE_UNIFORM: binBodyInput.compartments = uniformCompartments(binBodyInput.compartmentsByX, binBodyInput.compartmentsByY) diff --git a/lib/gridfinityUtils/baseGenerator.py b/lib/gridfinityUtils/baseGenerator.py index 802649c..bce87c6 100644 --- a/lib/gridfinityUtils/baseGenerator.py +++ b/lib/gridfinityUtils/baseGenerator.py @@ -403,8 +403,8 @@ def cutBaseClearance( basesYCount, targetComponent: adsk.fusion.Component, ): - actual_base_width = baseConfiguration.baseWidth * basesXCount - baseConfiguration.xyClearance * 2 - actual_base_length = baseConfiguration.baseLength * basesYCount - baseConfiguration.xyClearance * 2 + actual_base_width = baseConfiguration.baseWidth * basesXCount + baseConfiguration.paddingLeft + baseConfiguration.paddingRight - baseConfiguration.xyClearance * 2 + actual_base_length = baseConfiguration.baseLength * basesYCount + baseConfiguration.paddingTop + baseConfiguration.paddingBottom - baseConfiguration.xyClearance * 2 features = targetComponent.features baseConstructionPlaneInput: adsk.fusion.ConstructionPlaneInput = targetComponent.constructionPlanes.createInput() baseConstructionPlaneInput.setByOffset(targetComponent.xYConstructionPlane, adsk.core.ValueInput.createByReal(baseConfiguration.originPoint.z)) @@ -416,8 +416,8 @@ def cutBaseClearance( actual_base_width, actual_base_length, adsk.core.Point3D.create( - baseConfiguration.originPoint.x + baseConfiguration.xyClearance, - baseConfiguration.originPoint.y + baseConfiguration.xyClearance, + baseConfiguration.originPoint.x + baseConfiguration.xyClearance - baseConfiguration.paddingLeft, + baseConfiguration.originPoint.y + baseConfiguration.xyClearance - baseConfiguration.paddingBottom, baseConfiguration.originPoint.z, ), baseClearanceCutSketch @@ -438,7 +438,15 @@ def cutBaseClearance( geometricConstraints.addEqual(fillet3, fillet4) sketchDimensions.addRadialDimension(fillet1, fillet1.startSketchPoint.geometry) - baseClearanceCutSketch.offset(commonUtils.objectCollectionFromList([fillet1, fillet2, fillet3, fillet4, side1, side2, side3, side4]), baseConfiguration.originPoint, 1) + baseClearanceCutSketch.offset( + commonUtils.objectCollectionFromList([fillet1, fillet2, fillet3, fillet4, side1, side2, side3, side4]), + adsk.core.Point3D.create( + baseConfiguration.originPoint.x - baseConfiguration.paddingLeft, + baseConfiguration.originPoint.y - baseConfiguration.paddingBottom, + baseConfiguration.originPoint.z, + ), + 1 + ) cuttingProfile = min(list(baseClearanceCutSketch.profiles), key=lambda x: x.boundingBox.minPoint.x) clearanceCutExtrudeInput = features.extrudeFeatures.createInput( diff --git a/lib/gridfinityUtils/baseGeneratorInput.py b/lib/gridfinityUtils/baseGeneratorInput.py index 1bec31c..1af424b 100644 --- a/lib/gridfinityUtils/baseGeneratorInput.py +++ b/lib/gridfinityUtils/baseGeneratorInput.py @@ -11,6 +11,11 @@ def __init__(self): self.magnetCutoutsDiameter = DIMENSION_MAGNET_CUTOUT_DIAMETER self.magnetCutoutsDepth = DIMENSION_MAGNET_CUTOUT_DEPTH self.cornerFilletRadius = BIN_CORNER_FILLET_RADIUS + self.hasPadding = False + self.paddingLeft = 0 + self.paddingTop = 0 + self.paddingRight = 0 + self.paddingBottom = 0 @property def originPoint(self) -> adsk.core.Point3D: @@ -98,4 +103,44 @@ def magnetCutoutsDepth(self) -> float: @magnetCutoutsDepth.setter def magnetCutoutsDepth(self, value: float): - self._magnetCutoutsDepth = value \ No newline at end of file + self._magnetCutoutsDepth = value + + @property + def hasPadding(self) -> bool: + return self._hasPadding + + @hasPadding.setter + def hasPadding(self, value: bool): + self._hasPadding = value + + @property + def paddingLeft(self) -> float: + return self._paddingLeft if self._hasPadding else 0 + + @paddingLeft.setter + def paddingLeft(self, value: float): + self._paddingLeft = value + + @property + def paddingTop(self) -> float: + return self._paddingTop if self._hasPadding else 0 + + @paddingTop.setter + def paddingTop(self, value: float): + self._paddingTop = value + + @property + def paddingRight(self) -> float: + return self._paddingRight if self._hasPadding else 0 + + @paddingRight.setter + def paddingRight(self, value: float): + self._paddingRight = value + + @property + def paddingBottom(self) -> float: + return self._paddingBottom if self._hasPadding else 0 + + @paddingBottom.setter + def paddingBottom(self, value: float): + self._paddingBottom = value diff --git a/lib/gridfinityUtils/baseplateGeneratorInput.py b/lib/gridfinityUtils/baseplateGeneratorInput.py index ec58b69..79d228b 100644 --- a/lib/gridfinityUtils/baseplateGeneratorInput.py +++ b/lib/gridfinityUtils/baseplateGeneratorInput.py @@ -115,7 +115,7 @@ def hasPadding(self, value: bool): @property def paddingLeft(self) -> float: - return self._paddingLeft + return self._paddingLeft if self._hasPadding else 0 @paddingLeft.setter def paddingLeft(self, value: float): @@ -123,7 +123,7 @@ def paddingLeft(self, value: float): @property def paddingTop(self) -> float: - return self._paddingTop + return self._paddingTop if self._hasPadding else 0 @paddingTop.setter def paddingTop(self, value: float): @@ -131,7 +131,7 @@ def paddingTop(self, value: float): @property def paddingRight(self) -> float: - return self._paddingRight + return self._paddingRight if self._hasPadding else 0 @paddingRight.setter def paddingRight(self, value: float): @@ -139,7 +139,7 @@ def paddingRight(self, value: float): @property def paddingBottom(self) -> float: - return self._paddingBottom + return self._paddingBottom if self._hasPadding else 0 @paddingBottom.setter def paddingBottom(self, value: float): diff --git a/lib/gridfinityUtils/binBodyGenerator.py b/lib/gridfinityUtils/binBodyGenerator.py index fa13ecc..ef2f68e 100644 --- a/lib/gridfinityUtils/binBodyGenerator.py +++ b/lib/gridfinityUtils/binBodyGenerator.py @@ -30,17 +30,22 @@ def createGridfinityBinBody( targetComponent: adsk.fusion.Component, ) -> tuple[adsk.fusion.BRepBody, adsk.fusion.BRepBody]: - actualBodyWidth = (input.baseWidth * input.binWidth) - input.xyClearance * 2.0 - actualBodyLength = (input.baseLength * input.binLength) - input.xyClearance * 2.0 + actualBodyWidth = (input.baseWidth * input.binWidth) + input.paddingLeft + input.paddingRight - input.xyClearance * 2.0 + actualBodyLength = (input.baseLength * input.binLength) + input.paddingTop + input.paddingBottom - input.xyClearance * 2.0 binHeightWithoutBase = input.binHeight - 1 binBodyTotalHeight = binHeightWithoutBase * input.heightUnit + max(0, input.heightUnit - const.BIN_BASE_HEIGHT) features: adsk.fusion.Features = targetComponent.features - binBodyExtrude = extrudeUtils.createBox( + originPoint: adsk.core.Point3D = geometryUtils.createOffsetPoint( + targetComponent.originConstructionPoint.geometry, + byX=-input.paddingLeft, + byY=-input.paddingBottom, + ) + binBodyExtrude = extrudeUtils.createBoxAtPoint( actualBodyWidth, actualBodyLength, binBodyTotalHeight, targetComponent, - targetComponent.xYConstructionPlane + originPoint, ) binBody = binBodyExtrude.bodies.item(0) binBody.name = 'Bin body' @@ -58,8 +63,8 @@ def createGridfinityBinBody( if input.hasLip: lipOriginPoint = adsk.core.Point3D.create( - 0, - 0, + -input.paddingLeft, + -input.paddingBottom, binHeightWithoutBase * input.heightUnit + max(0, input.heightUnit - const.BIN_BASE_HEIGHT) ) lipInput = BinBodyLipGeneratorInput() @@ -71,6 +76,11 @@ def createGridfinityBinBody( lipInput.xyClearance = input.xyClearance lipInput.binCornerFilletRadius = input.binCornerFilletRadius lipInput.origin = lipOriginPoint + lipInput.hasPadding = input.hasPadding + lipInput.paddingLeft = input.paddingLeft + lipInput.paddingTop = input.paddingTop + lipInput.paddingRight = input.paddingRight + lipInput.paddingBottom = input.paddingBottom lipBody = createGridfinityBinBodyLip(lipInput, targetComponent) if input.wallThickness < const.BIN_LIP_WALL_THICKNESS: @@ -81,8 +91,8 @@ def createGridfinityBinBody( lipBottomChamferSize, targetComponent, adsk.core.Point3D.create( - input.wallThickness, - (const.BIN_LIP_WALL_THICKNESS - input.xyClearance) if input.hasScoop else input.wallThickness, + input.wallThickness - input.paddingLeft, + (const.BIN_LIP_WALL_THICKNESS - input.xyClearance - input.paddingBottom) if input.hasScoop else input.wallThickness - input.paddingBottom, lipOriginPoint.z, ) ) @@ -122,8 +132,8 @@ def createGridfinityBinBody( compartmentLengthUnit = (totalCompartmentsLength - (input.compartmentsByY - 1) * input.wallThickness) / input.compartmentsByY for compartment in input.compartments: - compartmentX = compartmentsMinX + compartment.positionX * (compartmentWidthUnit + input.wallThickness) - compartmentY = compartmentsMinY + compartment.positionY * (compartmentLengthUnit + input.wallThickness) + compartmentX = compartmentsMinX + compartment.positionX * (compartmentWidthUnit + input.wallThickness) - input.paddingLeft + compartmentY = compartmentsMinY + compartment.positionY * (compartmentLengthUnit + input.wallThickness) - input.paddingBottom compartmentOriginPoint = adsk.core.Point3D.create( compartmentX, compartmentY, @@ -165,8 +175,8 @@ def createGridfinityBinBody( compartmentsTopClearance = createCompartmentCutout( input.wallThickness, adsk.core.Point3D.create( - compartmentsMinX, - compartmentsMinY, + compartmentsMinX - input.paddingLeft, + compartmentsMinY - input.paddingBottom, binBodyTotalHeight ), actualBodyWidth - input.wallThickness * 2, diff --git a/lib/gridfinityUtils/binBodyGeneratorInput.py b/lib/gridfinityUtils/binBodyGeneratorInput.py index 40eed7c..bd12dd0 100644 --- a/lib/gridfinityUtils/binBodyGeneratorInput.py +++ b/lib/gridfinityUtils/binBodyGeneratorInput.py @@ -67,6 +67,11 @@ def __init__(self): self.compartmentsByX = 1 self.compartmentsByY = 1 self.binCornerFilletRadius = const.BIN_CORNER_FILLET_RADIUS + self.hasPadding = False + self.paddingLeft = 0 + self.paddingTop = 0 + self.paddingRight = 0 + self.paddingBottom = 0 @property def baseWidth(self) -> float: @@ -243,3 +248,44 @@ def compartments(self) -> list[BinBodyCompartmentDefinition]: @compartments.setter def compartments(self, value: list[BinBodyCompartmentDefinition]): self._compartments = value + + + @property + def hasPadding(self) -> bool: + return self._hasPadding + + @hasPadding.setter + def hasPadding(self, value: bool): + self._hasPadding = value + + @property + def paddingLeft(self) -> float: + return self._paddingLeft if self._hasPadding else 0 + + @paddingLeft.setter + def paddingLeft(self, value: float): + self._paddingLeft = value + + @property + def paddingTop(self) -> float: + return self._paddingTop if self._hasPadding else 0 + + @paddingTop.setter + def paddingTop(self, value: float): + self._paddingTop = value + + @property + def paddingRight(self) -> float: + return self._paddingRight if self._hasPadding else 0 + + @paddingRight.setter + def paddingRight(self, value: float): + self._paddingRight = value + + @property + def paddingBottom(self) -> float: + return self._paddingBottom if self._hasPadding else 0 + + @paddingBottom.setter + def paddingBottom(self, value: float): + self._paddingBottom = value diff --git a/lib/gridfinityUtils/binBodyLipGenerator.py b/lib/gridfinityUtils/binBodyLipGenerator.py index 0e475f5..897b1a9 100644 --- a/lib/gridfinityUtils/binBodyLipGenerator.py +++ b/lib/gridfinityUtils/binBodyLipGenerator.py @@ -22,8 +22,8 @@ def createGridfinityBinBodyLip( input: BinBodyLipGeneratorInput, targetComponent: adsk.fusion.Component, ): - actualLipBodyWidth = (input.baseWidth * input.binWidth) - input.xyClearance * 2.0 - actualLipBodyLength = (input.baseLength * input.binLength) - input.xyClearance * 2.0 + actualLipBodyWidth = (input.baseWidth * input.binWidth) + input.paddingLeft + input.paddingRight - input.xyClearance * 2.0 + actualLipBodyLength = (input.baseLength * input.binLength) + input.paddingTop + input.paddingBottom - input.xyClearance * 2.0 lipBodyHeight = const.BIN_LIP_EXTRA_HEIGHT features: adsk.fusion.Features = targetComponent.features @@ -62,8 +62,8 @@ def createGridfinityBinBodyLip( byY=-input.xyClearance * 2, byZ=const.BIN_BASE_HEIGHT ) - lipCutoutInput.baseWidth = input.baseWidth + input.xyClearance * 2 - lipCutoutInput.baseLength = input.baseLength + input.xyClearance * 2 + lipCutoutInput.baseWidth = input.baseWidth + input.paddingLeft + input.paddingRight + input.xyClearance * 2 + lipCutoutInput.baseLength = input.baseLength + input.paddingTop + input.paddingBottom + input.xyClearance * 2 lipCutoutInput.xyClearance = input.xyClearance lipCutoutInput.hasBottomChamfer = False lipCutoutInput.cornerFilletRadius = input.binCornerFilletRadius + input.xyClearance * 2 @@ -113,8 +113,8 @@ def createGridfinityBinBodyLip( byY=-input.xyClearance * 2, byZ=const.BIN_BASE_HEIGHT ) - lipCutoutInput.baseWidth = input.baseWidth * input.binWidth + input.xyClearance * 2 - lipCutoutInput.baseLength = input.baseLength * input.binLength + input.xyClearance * 2 + lipCutoutInput.baseWidth = input.baseWidth * input.binWidth + input.paddingLeft + input.paddingRight + input.xyClearance * 2 + lipCutoutInput.baseLength = input.baseLength * input.binLength + input.paddingTop + input.paddingBottom + input.xyClearance * 2 lipCutoutInput.xyClearance = input.xyClearance lipCutoutInput.hasBottomChamfer = False lipCutoutInput.cornerFilletRadius = input.binCornerFilletRadius + input.xyClearance * 2 @@ -130,7 +130,7 @@ def createGridfinityBinBodyLip( sketchUtils.createRectangle( actualLipBodyWidth, actualLipBodyLength, - topChamferSketch.modelToSketchSpace(adsk.core.Point3D.create(0, 0, topChamferSketch.origin.z)), + topChamferSketch.modelToSketchSpace(adsk.core.Point3D.create(-input.paddingLeft, -input.paddingBottom, topChamferSketch.origin.z)), topChamferSketch, ) topChamferNegativeVolume = extrudeUtils.simpleDistanceExtrude( diff --git a/lib/gridfinityUtils/binBodyLipGeneratorInput.py b/lib/gridfinityUtils/binBodyLipGeneratorInput.py index 06d1360..dee3d51 100644 --- a/lib/gridfinityUtils/binBodyLipGeneratorInput.py +++ b/lib/gridfinityUtils/binBodyLipGeneratorInput.py @@ -8,6 +8,11 @@ def __init__(self): self.hasLip = False self.hasLipNotches = False self.binCornerFilletRadius = const.BIN_CORNER_FILLET_RADIUS + self.hasPadding = False + self.paddingLeft = 0 + self.paddingTop = 0 + self.paddingRight = 0 + self.paddingBottom = 0 @property def baseWidth(self) -> float: @@ -79,4 +84,44 @@ def origin(self) -> adsk.core.Point3D: @origin.setter def origin(self, value: adsk.core.Point3D): - self._originUnit = value \ No newline at end of file + self._originUnit = value + + @property + def hasPadding(self) -> bool: + return self._hasPadding + + @hasPadding.setter + def hasPadding(self, value: bool): + self._hasPadding = value + + @property + def paddingLeft(self) -> float: + return self._paddingLeft if self._hasPadding else 0 + + @paddingLeft.setter + def paddingLeft(self, value: float): + self._paddingLeft = value + + @property + def paddingTop(self) -> float: + return self._paddingTop if self._hasPadding else 0 + + @paddingTop.setter + def paddingTop(self, value: float): + self._paddingTop = value + + @property + def paddingRight(self) -> float: + return self._paddingRight if self._hasPadding else 0 + + @paddingRight.setter + def paddingRight(self, value: float): + self._paddingRight = value + + @property + def paddingBottom(self) -> float: + return self._paddingBottom if self._hasPadding else 0 + + @paddingBottom.setter + def paddingBottom(self, value: float): + self._paddingBottom = value