305 lines
10 KiB
Python
305 lines
10 KiB
Python
#! python
|
|
|
|
"""
|
|
Classes for handling model inputs to Manufacturing Advisor function calling
|
|
tools.
|
|
|
|
- Construct a ModelInput instance by calling extractModelInput() with a 'model'
|
|
dictionary argument.
|
|
- The ModelInput mode is NONE if no models are to be added to the setup.
|
|
- Call attachModelToSetupInput() to attach the model input configuration to
|
|
a SetupInput instance. This returns True if models were successfully added
|
|
(or nothing added with CAMFunctionContext warnings, allowing setup creation
|
|
to continue).
|
|
"""
|
|
|
|
from adsk.cam import CAM, SetupInput
|
|
from adsk.core import Selections, UserInterface
|
|
from adsk.fusion import BRepBody, Component, Design, Occurrence
|
|
from CAMFunctionContext import CAMFunctionContext
|
|
from CAMFunctionUtils import (
|
|
ModelInputMode,
|
|
areMatchingCaseInsensitiveNames,
|
|
getManufacturingModelByName,
|
|
getValidOccurrences,
|
|
)
|
|
|
|
|
|
class ModelInput:
|
|
"""
|
|
Represents a model input configuration.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
mode: ModelInputMode,
|
|
occurrenceName: str | None = None,
|
|
manufacturingModelName: str | None = None,
|
|
):
|
|
"""
|
|
Initializes a ModelInput instance.
|
|
"""
|
|
self.mode: ModelInputMode = mode
|
|
self.occurrenceName: str | None = occurrenceName
|
|
self.manufacturingModelName: str | None = manufacturingModelName
|
|
|
|
def attachModelToSetupInput(
|
|
self,
|
|
ui: UserInterface,
|
|
cam: CAM,
|
|
errorMessage: str,
|
|
warningMessage: str,
|
|
setupInput: SetupInput,
|
|
) -> bool:
|
|
"""
|
|
Attaches the model input configuration to the given setup input.
|
|
|
|
- Returns True if models were successfully added (or nothing added with
|
|
CAMFunctionContext warnings, allowing setup creation to continue).
|
|
- Returns False otherwise (with errors added to CAMFunctionContext).
|
|
"""
|
|
match self.mode:
|
|
case ModelInputMode.NONE:
|
|
return True # No models to add
|
|
case ModelInputMode.ALL:
|
|
return self._addAllOccurrences(
|
|
cam=cam,
|
|
setupInput=setupInput,
|
|
)
|
|
case ModelInputMode.NAMED:
|
|
return self._addNamedOccurrence(
|
|
cam=cam,
|
|
errorMessage=errorMessage,
|
|
warningMessage=warningMessage,
|
|
setupInput=setupInput,
|
|
)
|
|
case ModelInputMode.MANUFACTURING_MODEL:
|
|
return self._addManufacturingModelOccurrences(
|
|
cam=cam,
|
|
errorMessage=errorMessage,
|
|
setupInput=setupInput,
|
|
)
|
|
case ModelInputMode.ACTIVE_SELECTION:
|
|
return self._addActiveSelectionOccurrences(
|
|
ui=ui,
|
|
errorMessage=errorMessage,
|
|
setupInput=setupInput,
|
|
)
|
|
|
|
return False
|
|
|
|
@classmethod
|
|
def _addAllOccurrences(
|
|
cls,
|
|
cam: CAM,
|
|
setupInput: SetupInput,
|
|
) -> bool:
|
|
"""
|
|
Adds all models to the setup input.
|
|
|
|
This is done by getting access to the the root component of the CAM
|
|
product. We can get this by getting the assembly context of the design
|
|
root occurrence - but fall back to the design root occurrence for
|
|
safety.
|
|
"""
|
|
|
|
rootOccurrence: Occurrence = cam.designRootOccurrence
|
|
camRootOccurrence: Occurrence = rootOccurrence.assemblyContext
|
|
setupInput.models = (
|
|
[camRootOccurrence] if camRootOccurrence else [rootOccurrence]
|
|
)
|
|
return True
|
|
|
|
def _addNamedOccurrence(
|
|
self,
|
|
cam: CAM,
|
|
errorMessage: str,
|
|
warningMessage: str,
|
|
setupInput: SetupInput,
|
|
) -> bool:
|
|
"""
|
|
Adds a named occurrence to the setup input.
|
|
|
|
- Returns True if the occurrence was found and added.
|
|
- Returns True with a warning if the occurrence was not found.
|
|
- Returns False with an error if the occurrence name was not provided.
|
|
"""
|
|
|
|
if not self.occurrenceName:
|
|
CAMFunctionContext.fail(
|
|
message=errorMessage,
|
|
error="Name is not provided",
|
|
)
|
|
return False
|
|
|
|
target: BRepBody | Occurrence | None = self._findComponentOccurrenceOrBodyByName(
|
|
occurrence=cam.designRootOccurrence,
|
|
name=self.occurrenceName,
|
|
)
|
|
if not target:
|
|
CAMFunctionContext.warn(
|
|
message=warningMessage,
|
|
warning=f"Occurrence with name '{self.occurrenceName}' does not exist.",
|
|
)
|
|
return True # No bodies added, but not a failure
|
|
|
|
setupInput.models = [target]
|
|
return True
|
|
|
|
def _addManufacturingModelOccurrences(
|
|
self,
|
|
cam: CAM,
|
|
errorMessage: str,
|
|
setupInput: SetupInput,
|
|
) -> bool:
|
|
"""
|
|
Adds occurrences from a manufacturing model to the setup input.
|
|
|
|
- Returns True if occurrences were found and added.
|
|
- Returns False with an error if the manufacturing model name was not
|
|
provided.
|
|
- Returns False with an error if the manufacturing model was not found.
|
|
- Returns False with an error if the manufacturing model has no valid
|
|
occurrences.
|
|
"""
|
|
|
|
if not self.manufacturingModelName:
|
|
CAMFunctionContext.fail(
|
|
message=errorMessage,
|
|
error="Manufacturing model name is not provided.",
|
|
)
|
|
return False
|
|
|
|
manufacturingModel = getManufacturingModelByName(
|
|
cam=cam,
|
|
name=self.manufacturingModelName,
|
|
)
|
|
if not manufacturingModel:
|
|
CAMFunctionContext.fail(
|
|
message=errorMessage,
|
|
error=f"Manufacturing model '{self.manufacturingModelName}' not found.",
|
|
)
|
|
return False
|
|
|
|
occs = getValidOccurrences(manufacturingModel.occurrence)
|
|
if len(occs) == 0:
|
|
CAMFunctionContext.fail(
|
|
message=errorMessage,
|
|
error=f"Manufacturing model '{manufacturingModel.name}' has no valid occurrences.",
|
|
)
|
|
return False
|
|
|
|
setupInput.models = occs
|
|
return True
|
|
|
|
@classmethod
|
|
def _addActiveSelectionOccurrences(
|
|
cls,
|
|
ui: UserInterface,
|
|
errorMessage: str,
|
|
setupInput: SetupInput,
|
|
) -> bool:
|
|
"""
|
|
Adds occurrences from the active selection to the setup input.
|
|
|
|
- Returns True if models were successfully added.
|
|
- Returns False if no active selections were found (with errors added
|
|
to CAMFunctionContext).
|
|
- Returns True if no valid bodies or components were found in the
|
|
active selection.
|
|
"""
|
|
|
|
selections: Selections = ui.activeSelections
|
|
if selections.count == 0:
|
|
CAMFunctionContext.fail(
|
|
message=errorMessage,
|
|
error="No active selections found.",
|
|
)
|
|
return False
|
|
|
|
selectedObjects = []
|
|
for selection in selections:
|
|
entity = selection.entity
|
|
if isinstance(entity, (BRepBody, Occurrence)):
|
|
selectedObjects.append(entity)
|
|
|
|
if len(selectedObjects) == 0:
|
|
CAMFunctionContext.warn(
|
|
message=errorMessage,
|
|
warning="No valid bodies or components found in active selections.",
|
|
)
|
|
return True # No occurrences/bodies added from selection, but not a failure
|
|
|
|
setupInput.models = selectedObjects
|
|
return True
|
|
|
|
@classmethod
|
|
def _findBodyByName(cls, component: Component, name: str) -> BRepBody | None:
|
|
"""
|
|
Finds a body by (case-insensitive) name within a component.
|
|
"""
|
|
for body in component.bRepBodies:
|
|
if areMatchingCaseInsensitiveNames(body.name, name):
|
|
return body
|
|
|
|
return None
|
|
|
|
@classmethod
|
|
def _findComponentOccurrenceOrBodyByName(
|
|
cls,
|
|
occurrence: Occurrence,
|
|
name: str,
|
|
) -> BRepBody | Occurrence | None:
|
|
"""
|
|
Find the occurrence of a component or a body by (case-insensitive) name
|
|
within the given occurrence recursively.
|
|
"""
|
|
|
|
component: Component = occurrence.component
|
|
if areMatchingCaseInsensitiveNames(component.name, name):
|
|
return occurrence
|
|
|
|
body: BRepBody | None = cls._findBodyByName(component, name)
|
|
if body:
|
|
return body
|
|
|
|
for childOccurrence in occurrence.childOccurrences:
|
|
result = cls._findComponentOccurrenceOrBodyByName(
|
|
occurrence=childOccurrence,
|
|
name=name,
|
|
)
|
|
if result:
|
|
return result
|
|
|
|
return None
|
|
|
|
|
|
def extractModelInput(modelInputDict: dict | None) -> ModelInput:
|
|
"""
|
|
Extracts a ModelInput instance from the given dictionary.
|
|
|
|
Returns a ModelInput instance with mode NONE if the dictionary is invalid,
|
|
or if the mode is invalid.
|
|
"""
|
|
|
|
mode: ModelInputMode = ModelInputMode.NONE
|
|
occurrenceName: str | None = None
|
|
manufacturingModelName: str | None = None
|
|
|
|
if isinstance(modelInputDict, dict):
|
|
modeStr: str = modelInputDict.get("mode", "none")
|
|
try:
|
|
mode = ModelInputMode(modeStr)
|
|
except ValueError:
|
|
mode = ModelInputMode.NONE
|
|
|
|
if mode != ModelInputMode.NONE:
|
|
occurrenceName = modelInputDict.get("occurrence_name")
|
|
manufacturingModelName = modelInputDict.get("manufacturing_model_name")
|
|
|
|
return ModelInput(
|
|
mode=mode,
|
|
occurrenceName=occurrenceName,
|
|
manufacturingModelName=manufacturingModelName,
|
|
)
|