#Author-Autodesk Inc. #Description-Demo custom graphics examples import adsk.core, adsk.fusion, adsk.cam, traceback import math # Globals _app = adsk.core.Application.cast(None) _ui = adsk.core.UserInterface.cast(None) _des = adsk.fusion.Design.cast(None) _cgGroups = adsk.fusion.CustomGraphicsGroups.cast(None) _numTeeth = 5 _handlers = [] appearancesMap = {} _pointSetImage = './resources/16x16.png' _thickness = 0.5 * 2.54 _anchorPt = adsk.core.Point3D.cast(None) #_scaleFactor is used to limit the size of pixel-scaled model however large the actual graphics model. _scaleFactor = 10 _commandId = 'CustomGraphicsSample_Python' _colorEffect_solid_id = 'SolidColorEfect' _colorEffect_basicMaterial_id = 'BasicMaterialColorEffect' _colorEffect_appearance_id = 'AppearanceColorEffect' _colorEffect_vertex_id = 'VertexColorEffect' # Global Command inputs _customGraphicsObj = adsk.core.DropDownCommandInput.cast(None) _colorEffects = adsk.core.DropDownCommandInput.cast(None) _red = adsk.core.IntegerSliderCommandInput.cast(None) _green = adsk.core.IntegerSliderCommandInput.cast(None) _blue = adsk.core.IntegerSliderCommandInput.cast(None) _opacity = adsk.core.SliderCommandInput.cast(None) _glossiness = adsk.core.SliderCommandInput.cast(None) _selection = adsk.core.SelectionCommandInput.cast(None) _transform = adsk.core.DistanceValueCommandInput.cast(None) _materialLibList = adsk.core.DropDownCommandInput.cast(None) _appearanceList = adsk.core.DropDownCommandInput.cast(None) _appearanceFilter = adsk.core.StringValueCommandInput.cast(None) _coordTable = adsk.core.TableCommandInput.cast(None) _add = adsk.core.BoolValueCommandInput.cast(None) _addStrip = adsk.core.BoolValueCommandInput.cast(None) _delete = adsk.core.BoolValueCommandInput.cast(None) _isLineStrip = adsk.core.BoolValueCommandInput.cast(None) _lineStylePattern = adsk.core.DropDownCommandInput.cast(None) _lineStyleWeight = adsk.core.IntegerSliderCommandInput.cast(None) _lineStyleScale = adsk.core.IntegerSliderCommandInput.cast(None) _viewPlacementGroup = adsk.core.GroupCommandInput.cast(None) _viewCorner = adsk.core.ButtonRowCommandInput.cast(None) _viewScaleGroup = adsk.core.GroupCommandInput.cast(None) _pixelScale = adsk.core.FloatSliderCommandInput.cast(None) _billboardingGroup = adsk.core.GroupCommandInput.cast(None) _billboardingStyle = adsk.core.ButtonRowCommandInput.cast(None) _text = adsk.core.StringValueCommandInput.cast(None) _textSize = adsk.core.ValueCommandInput.cast(None) _textStyle = adsk.core.ButtonRowCommandInput.cast(None) _textFont = adsk.core.StringValueCommandInput.cast(None) def run(context): try: global _app, _ui, _des, _cgGroups, coordNumber,stripNumber coordNumber = 0 stripNumber = 0 _app = adsk.core.Application.get() _ui = _app.userInterface doc = _app.activeDocument prods = doc.products _des = prods.itemByProductType('DesignProductType') if not _des: raise Exception('Failed to get fusion design.') # get the entry for custom graphics activeProd = _app.activeProduct cam = adsk.cam.CAM.cast(activeProd) if cam: _cgGroups = cam.customGraphicsGroups else: _cgGroups = _des.rootComponent.customGraphicsGroups cmdDef = _ui.commandDefinitions.itemById(_commandId) if not cmdDef: # Create a command definition. cmdDef = _ui.commandDefinitions.addButtonDefinition(_commandId, 'CustomGraphicsSample', 'Custom Graphics Sample') # Connect to the command created event. onCommandCreated = MyCommandCreatedHandler() cmdDef.commandCreated.add(onCommandCreated) _handlers.append(onCommandCreated) # Execute the command. cmdDef.execute() # prevent this module from being terminate when the script returns, because we are waiting for event handlers to fire adsk.autoTerminate(False) except: if _ui: _ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) class MyCommandDestroyHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: # eventArgs = adsk.core.CommandEventArgs.cast(args) # when the command is done, terminate the script # this will release all globals which will remove all event handlers adsk.terminate() except: if _ui: _ui.messageBox('Failed in MyCommandDestroyHandler:\n{}'.format(traceback.format_exc())) def addRow(tableInput): global coordNumber tableChildInputs = tableInput.commandInputs xValueInput = tableChildInputs.addValueInput(_coordTable.id + '_x{}'.format(coordNumber), 'Value', 'cm', adsk.core.ValueInput.createByReal(coordNumber)) yValueInput = tableChildInputs.addValueInput(_coordTable.id + '_y{}'.format(coordNumber), 'Value', 'cm', adsk.core.ValueInput.createByReal(coordNumber)) zValueInput = tableChildInputs.addValueInput(_coordTable.id + '_z{}'.format(coordNumber), 'Value', 'cm', adsk.core.ValueInput.createByReal(coordNumber)) row = tableInput.rowCount tableInput.addCommandInput(xValueInput, row, 0) tableInput.addCommandInput(yValueInput, row, 1) tableInput.addCommandInput(zValueInput, row, 2) coordNumber = coordNumber + 1 def addLineStrip(tableInput): global stripNumber tableChildInputs = tableInput.commandInputs strInput = tableChildInputs.addStringValueInput(_coordTable.id + '_strip{}'.format(stripNumber), 'Line Strip', '-- Line Strip --') strInput.isReadOnly = True row = tableInput.rowCount tableInput.addCommandInput(strInput, row, 0, 0, 2) stripNumber = stripNumber + 1 def replaceItems(cmdInput, newItems): try: cmdInput.listItems.clear() itemNone = cmdInput.listItems.add('None', True, '') itemNone.isSelected = True if len(newItems) > 0: for item in newItems: cmdInput.listItems.add(item, False, '') cmdInput.listItems[1].isSelected = True cmdInput.listItems[0].deleteMe() except: if _ui: _ui.messageBox('Failed in replaceItems:\n{}'.format(traceback.format_exc())) def getAppearancesFromLib(libName, filterExp): try: global appearancesMap appearanceList = None if libName in appearancesMap: appearanceList = appearancesMap[libName] else: materialLib = _app.materialLibraries.itemByName(libName) appearances = materialLib.appearances appearanceNames = [] for appearance in appearances: appearanceNames.append(appearance.name) appearancesMap[libName] = appearanceNames appearanceList = appearanceNames if filterExp and len(filterExp) > 0: filteredList = [] for appearanceName in appearanceList: if appearanceName.lower().find(filterExp.lower()) >= 0: filteredList.append(appearanceName) return filteredList else: return appearanceList except: if _ui: _ui.messageBox('Failed in getAppearancesFromLib:\n{}'.format(traceback.format_exc())) def hasAppearances(lib): if lib and lib.appearances.count > 0: return True return False def getMaterialLibNames(libFilter): materialLibs = _app.materialLibraries libNames = [] for materialLib in materialLibs: if (not libFilter) or libFilter(materialLib): libNames.append(materialLib.name) return libNames def getAppearance(libName, appearanceName): try: if not appearanceName or appearanceName == 'None': return appearance = _des.appearances.itemByName(appearanceName) if appearance: return appearance matLib = _app.materialLibraries.itemByName(libName) if matLib: appearance = matLib.appearances.itemByName(appearanceName) return appearance except: if _ui: _ui.messageBox('Failed in getAppearance:\n{}'.format(traceback.format_exc())) # Event handler for the commandCreated event. class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler): def __init__(self): super().__init__() def notify(self, args): try: eventArgs = adsk.core.CommandCreatedEventArgs.cast(args) # Verify that a Fusion design is active. if not _des: _ui.messageBox('A Fusion design must be active when invoking this command.') return() cmd = eventArgs.command cmd.isExecutedWhenPreEmpted = False inputs = cmd.commandInputs global _customGraphicsObj, _selection, _coordTable, _add, _delete global _colorEffects,_glossiness, _opacity, _transform, _isLineStrip, _addStrip, _lineStyleWeight, _lineStyleScale, _lineStylePattern global _red,_green,_blue, _appearanceList, _materialLibList, _appearanceFilter global _text, _textSize, _textStyle, _textFont # menu for different kinds of custom graphics _customGraphicsObj = inputs.addDropDownCommandInput(_commandId + '_cgObj', 'Custom Graphics Object', adsk.core.DropDownStyles.TextListDropDownStyle) _customGraphicsObj.listItems.add('Mesh', True) _customGraphicsObj.listItems.add('Lines', False) _customGraphicsObj.listItems.add('PointSet', False) _customGraphicsObj.listItems.add('Curve', False) _customGraphicsObj.listItems.add('BRep', False) _customGraphicsObj.listItems.add('Text', False) _customGraphicsObj.listItems.add('Lines - Custom', False) _customGraphicsObj.listItems.add('PointSet - Custom', False) # coordinates table used by 'Lines - Custom' and 'PointSet - Custom' _coordTable = inputs.addTableCommandInput(_commandId + '_table', 'Coordinates Table', 3, '1:1:1') _coordTable.maximumVisibleRows = 10 addRow(_coordTable) _add = inputs.addBoolValueInput(_coordTable.id + '_add', 'Add', False, '', True) _coordTable.addToolbarCommandInput(_add) _addStrip = inputs.addBoolValueInput(_coordTable.id + '_addStrip', 'AddStrip', False, '', True) _coordTable.addToolbarCommandInput(_addStrip) _delete = inputs.addBoolValueInput(_coordTable.id + '_delete', 'Delete', False, '', True) _coordTable.addToolbarCommandInput(_delete) _coordTable.isVisible = False _add.isVisible = False _delete.isVisible = False _addStrip.isVisible = False # specific for 'Lines - Custom' _isLineStrip = inputs.addBoolValueInput(_commandId + '_isLineStrip', 'Use LineStrip', True, '', True) _isLineStrip.isVisible = False # color effects for custom graphics Mesh/BRep _colorEffects = inputs.addDropDownCommandInput(_commandId + '_colorEffects', 'Color Effect', adsk.core.DropDownStyles.TextListDropDownStyle) _colorEffects.listItems.add(_colorEffect_solid_id, True) _colorEffects.listItems.add(_colorEffect_basicMaterial_id, False) _colorEffects.listItems.add(_colorEffect_appearance_id, False) _colorEffects.listItems.add(_colorEffect_vertex_id, False) # RGB for solid colors _red = inputs.addIntegerSliderCommandInput(_commandId + '_red', 'Red', 0, 255, False) _red.valueOne = 255 _green = inputs.addIntegerSliderCommandInput(_commandId + '_green', 'Green', 0, 255, False) _green.valueOne = 0 _blue = inputs.addIntegerSliderCommandInput(_commandId + '_blue', 'Blue', 0, 255, False) _blue.valueOne = 0 # specific for basic material color effect _glossiness = inputs.addFloatSliderCommandInput(_commandId + '_glossiness', 'Glossiness', '', 0.0, 128.0, False) _glossiness.valueOne = 128.0 _glossiness.isVisible = False _opacity = inputs.addFloatSliderCommandInput(_commandId + '_opacity', 'Opacity', '', 0.0, 1.0, False) _opacity.valueOne = 1.0 _opacity.isVisible = False # for appearance color effect _materialLibList = inputs.addDropDownCommandInput(_commandId + '_materialLib', 'Material Library', adsk.core.DropDownStyles.TextListDropDownStyle) listItems = _materialLibList.listItems materialLibNames = getMaterialLibNames(hasAppearances) for materialName in materialLibNames: listItems.add(materialName, False, '') listItems[0].isSelected = True _materialLibList.isVisible = False _appearanceList = inputs.addDropDownCommandInput(_commandId + '_appearanceList', 'Appearance', adsk.core.DropDownStyles.TextListDropDownStyle) appearances = getAppearancesFromLib(materialLibNames[0], '') listItems = _appearanceList.listItems for appearanceName in appearances: listItems.add(appearanceName, False, '') listItems[0].isSelected = True _appearanceList.isVisible = False _appearanceFilter = inputs.addStringValueInput(_commandId + '_appearanceFilter', 'Filter', '') _appearanceFilter.isVisible = False # selection input for custom graphics BRep/Curve _selection = inputs.addSelectionInput(_commandId + '_sel', 'Selection', '') _selection.setSelectionLimits(0, 1) _selection.isVisible = False _selection.isEnabled = False # for custom graphics text txt = "{standard text}\P{\H1.5x;height:1.5x}\P{\C1;color:red}" \ + "\P{\H1;height:1 unit}\P{\T2;char spacing:2} " \ + "\P{\Q45;obliquing angle:45deg}\P{\W2;char width:2x}" \ + "\P{\\fArial;font:Arial}\~{\\fTimes;font:Times}\~{\\fCalibri;font:Calibri}"\ + "\P{\Ooverline\o}\~{\Lunderline\l}" _text = inputs.addStringValueInput(_commandId + '_text', 'Text', txt) _text.isVisible = False _textSize = inputs.addValueInput(_commandId + '_textSize', 'Size', 'cm', adsk.core.ValueInput.createByReal(1)) _textSize.isVisible = False _textStyle = inputs.addButtonRowCommandInput(_commandId + '_textStyle', 'Style', True) _textStyle.listItems.add('Bold', False, './resources/text_bold') _textStyle.listItems.add('Italic', False, './resources/text_italic') _textStyle.listItems.add('UnderLine', False, './resources/text_underline') _textStyle.listItems.add('StrikeThrough', False, './resources/text_strikethrough') _textStyle.isVisible = False _textFont = inputs.addStringValueInput(_commandId + '_textFont', 'Font', 'Arial') _textFont.isVisible = False # transform for all custom graphics entity _transform = inputs.addDistanceValueCommandInput(_commandId + '_transform', 'Transform', adsk.core.ValueInput.createByReal(0)) _transform.setManipulator( adsk.core.Point3D.create(0,0,0), adsk.core.Vector3D.create(1,0,0)) # menu for different kinds of line sytles _lineStylePattern = inputs.addDropDownCommandInput(_commandId + '_LSPattern', 'Line Style Pattern', adsk.core.DropDownStyles.TextListDropDownStyle) _lineStylePattern.listItems.add('Solid Line', True) _lineStylePattern.listItems.add('Center Line', False) _lineStylePattern.listItems.add('Dashed Line', False) _lineStylePattern.listItems.add('Dot Line', False) _lineStylePattern.listItems.add('Phantom Line', False) _lineStylePattern.listItems.add('Tracks Line', False) _lineStylePattern.listItems.add('ZigZag Line', False) _lineStylePattern.isVisible = False # for line sytle weight _lineStyleWeight = inputs.addIntegerSliderCommandInput(_commandId + '_LSWeight', 'Line Style Weight', 1, 20, False) _lineStyleWeight.valueOne = 1 _lineStyleWeight.isVisible = False # for line style scale _lineStyleScale = inputs.addIntegerSliderCommandInput(_commandId + '_LSScale', 'Line Style Scale', 1, 100, False) _lineStyleScale.valueOne = 10 _lineStyleScale.isVisible = False global _viewPlacementGroup, _viewCorner, _viewScaleGroup, _pixelScale, _billboardingGroup, _billboardingStyle # for view placement attribute _viewPlacementGroup = inputs.addGroupCommandInput(_commandId + '_VPGroup', 'View Placement') _viewPlacementGroup.isEnabledCheckBoxDisplayed = True _viewPlacementGroup.isEnabledCheckBoxChecked = False _viewCorner = _viewPlacementGroup.children.addButtonRowCommandInput(_commandId + '_viewCorner', 'corner', False) _viewCorner.listItems.add('Upper Left', False, './resources/upperLeft') _viewCorner.listItems.add('Upper Right', False, './resources/upperRight') _viewCorner.listItems.add('Lower Left', False, './resources/lowerLeft') _viewCorner.listItems.add('Lower Right', False, './resources/lowerRight') # for view scale attribute _viewScaleGroup = inputs.addGroupCommandInput(_commandId + '_VSGroup', 'View Scale') _viewScaleGroup.isEnabledCheckBoxDisplayed = True _viewScaleGroup.isEnabledCheckBoxChecked = False _pixelScale = _viewScaleGroup.children.addFloatSliderCommandInput(_commandId + '_pixelScale', 'pixel scale', '', 0.5, 5, False) _pixelScale.valueOne = 1 _pixelScale.setText('Smaller', 'Larger') # for billboarding attribute _billboardingGroup = inputs.addGroupCommandInput(_commandId + '_BBGroup', 'Billboarding') _billboardingGroup.isEnabledCheckBoxDisplayed = True _billboardingGroup.isEnabledCheckBoxChecked = False _billboardingStyle = _billboardingGroup.children.addButtonRowCommandInput(_commandId + '_billboardingStyle', 'style', False) _billboardingStyle.listItems.add('Screen', False, './resources/One') _billboardingStyle.listItems.add('Axis', False, './resources/Two') _billboardingStyle.listItems.add('Right Reading', False, './resources/Three') # Connect to the command related events. onExecute = MyCommandExecuteHandler() cmd.execute.add(onExecute) _handlers.append(onExecute) onExecutePreview = MyCommandExecuteHandler() cmd.executePreview.add(onExecutePreview) _handlers.append(onExecutePreview) onInputChanged = MyCommandInputChangedHandler() cmd.inputChanged.add(onInputChanged) _handlers.append(onInputChanged) onDestroy = MyCommandDestroyHandler() cmd.destroy.add(onDestroy) _handlers.append(onDestroy) except: if _ui: _ui.messageBox('Failed in MyCommandCreatedHandler:\n{}'.format(traceback.format_exc())) def applyLinesProperties(cgLines): try: if _lineStylePattern.selectedItem.name == 'Solid Line': cgLines.lineStylePattern = adsk.fusion.LineStylePatterns.continuousLineStylePattern elif _lineStylePattern.selectedItem.name == 'Center Line': cgLines.lineStylePattern = adsk.fusion.LineStylePatterns.centerLineStylePattern elif _lineStylePattern.selectedItem.name == 'Dashed Line': cgLines.lineStylePattern = adsk.fusion.LineStylePatterns.dashedLineStylePattern elif _lineStylePattern.selectedItem.name == 'Dot Line': cgLines.lineStylePattern = adsk.fusion.LineStylePatterns.dotLineStylePattern elif _lineStylePattern.selectedItem.name == 'Dashed Line': cgLines.lineStylePattern = adsk.fusion.LineStylePatterns.dashedLineStylePattern elif _lineStylePattern.selectedItem.name == 'Phantom Line': cgLines.lineStylePattern = adsk.fusion.LineStylePatterns.phantomLineStylePattern elif _lineStylePattern.selectedItem.name == 'Tracks Line': cgLines.lineStylePattern = adsk.fusion.LineStylePatterns.tracksLineStylePattern elif _lineStylePattern.selectedItem.name == 'ZigZag Line': cgLines.lineStylePattern = adsk.fusion.LineStylePatterns.zigzagLineStylePattern cgLines.weight = float(_lineStyleWeight.valueOne) cgLines.lineStyleScale = float(_lineStyleScale.valueOne) except: if _ui: _ui.messageBox('Failed in applyLinesProperties:\n{}'.format(traceback.format_exc())) def applyColorEffect(cgEnt): try: colorEffect = None if _colorEffects.selectedItem.name == _colorEffect_solid_id: colorEffect = adsk.fusion.CustomGraphicsSolidColorEffect.create(adsk.core.Color.create(int(_red.valueOne),int(_green.valueOne),int(_blue.valueOne),255)) elif _colorEffects.selectedItem.name == _colorEffect_basicMaterial_id: diffuseColor = adsk.core.Color.create(0,255,0,255) ambientColor = adsk.core.Color.create(255,0,0,255) specularColor = adsk.core.Color.create(0,0,255,255) emissiveColor = adsk.core.Color.create(0,0,0,255) colorEffect = adsk.fusion.CustomGraphicsBasicMaterialColorEffect.create(diffuseColor, ambientColor, specularColor, emissiveColor, float(_glossiness.valueOne), float(_opacity.valueOne)) elif _colorEffects.selectedItem.name == _colorEffect_appearance_id: appearance = getAppearance(_materialLibList.selectedItem.name, _appearanceList.selectedItem.name) if appearance: if not _des.appearances.itemByName(appearance.name): appearance = _des.appearances.addByCopy(appearance, appearance.name) colorEffect = adsk.fusion.CustomGraphicsAppearanceColorEffect.create(appearance) elif _colorEffects.selectedItem.name == _colorEffect_vertex_id: colorEffect = adsk.fusion.CustomGraphicsVertexColorEffect.create() if colorEffect: cgEnt.color = colorEffect except: if _ui: _ui.messageBox('Failed in applyColorEffect:\n{}'.format(traceback.format_exc())) def getCoordinatesFromTable(tableInput): try: vecCoord = [] vecStripLen = [] stripLen = 0 if _coordTable: for i in range(0, _coordTable.rowCount): xValueInput = adsk.core.ValueCommandInput.cast(_coordTable.getInputAtPosition(i,0)) if xValueInput: stripLen = stripLen + 1 yValueInput = adsk.core.ValueCommandInput.cast(_coordTable.getInputAtPosition(i,1)) zValueInput = adsk.core.ValueCommandInput.cast(_coordTable.getInputAtPosition(i,2)) vecCoord.extend([xValueInput.value, yValueInput.value, zValueInput.value]) else: vecStripLen.append(stripLen) stripLen = 0 vecStripLen.append(stripLen) return vecCoord, vecStripLen except: if _ui: _ui.messageBox('Failed in getCoordinatesFromTable:\n{}'.format(traceback.format_exc())) # Event handler for the execute event. class MyCommandExecuteHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: # get selection entity first since it's fragile and any creation/edit operations will clear the selection. selEntity = None if _selection.selectionCount > 0: selEntity = _selection.selection(0).entity if _customGraphicsObj: cgGroup = adsk.fusion.CustomGraphicsGroup.cast(_cgGroups.add()) global _anchorPt, _scaleFactor if not _anchorPt: _anchorPt = adsk.core.Point3D.create(0,0,0) cgEnt = None if _customGraphicsObj.selectedItem.name == 'Mesh': cgEnt = drawMesh(cgGroup) _anchorPt.setWithArray([0,0,_thickness/2]) elif _customGraphicsObj.selectedItem.name == 'Lines': cgEnt = drawLines(cgGroup) _anchorPt.setWithArray([0,0,_thickness/2]) applyLinesProperties(cgEnt) elif _customGraphicsObj.selectedItem.name == 'PointSet': cgEnt = drawPointSet(cgGroup) elif _customGraphicsObj.selectedItem.name == 'BRep': if selEntity: body = adsk.fusion.BRepBody.cast(selEntity) cgEnt = cgGroup.addBRepBody(body) elif _customGraphicsObj.selectedItem.name == 'Curve': if selEntity: skCurve = adsk.fusion.SketchCurve.cast(selEntity) sk = skCurve.parentSketch curve = skCurve.geometry curve.transformBy(sk.transform) cgEnt = cgGroup.addCurve(curve) cgEnt.weight = float(_lineStyleWeight.valueOne) elif _customGraphicsObj.selectedItem.name == 'Text': if _text.value: font = _textFont.value if _textFont.value else 'Arial' size = _textSize.value if _textSize.value > 0 else 1 cgText = adsk.fusion.CustomGraphicsText.cast(None) # In case font is invalid, we use 'Arial' as default one. try: cgEnt = cgText = cgGroup.addText(_text.value, font, size, adsk.core.Matrix3D.create()) except: cgEnt = cgText = cgGroup.addText(_text.value, 'Arial', size, adsk.core.Matrix3D.create()) for item in _textStyle.listItems: if item.name == 'Bold': cgText.isBold = True if item.isSelected else False elif item.name == 'Italic': cgText.isItalic = True if item.isSelected else False elif item.name == 'UnderLine': cgText.isUnderline = True if item.isSelected else False elif item.name == 'StrikeThrough': cgText.isStrikeThrough = True if item.isSelected else False elif _customGraphicsObj.selectedItem.name == 'PointSet - Custom': vecCoords, vecStripLen = getCoordinatesFromTable(_coordTable) coords = adsk.fusion.CustomGraphicsCoordinates.create(vecCoords) cgEnt = cgGroup.addPointSet(coords, [], adsk.fusion.CustomGraphicsPointTypes.UserDefinedCustomGraphicsPointType, _pointSetImage) elif _customGraphicsObj.selectedItem.name == 'Lines - Custom': vecCoords, vecStripLength = getCoordinatesFromTable(_coordTable) coords = adsk.fusion.CustomGraphicsCoordinates.create(vecCoords) isLineStrip = _isLineStrip.value if coords.coordinateCount < 1: return cgEnt = cgGroup.addLines(coords, [], isLineStrip, vecStripLength) applyLinesProperties(cgEnt) # add attributes to the custom graphics entity if cgEnt: # transform transMat = adsk.core.Matrix3D.create() origin = adsk.core.Point3D.create(float(_transform.value),0,0) transMat.setWithCoordinateSystem(origin, adsk.core.Vector3D.create(1,0,0), adsk.core.Vector3D.create(0,1,0), adsk.core.Vector3D.create(0,0,1)) cgEnt.transform = transMat # color effect if not adsk.fusion.CustomGraphicsPointSet.cast(cgEnt) and not adsk.fusion.CustomGraphicsText.cast(cgEnt): applyColorEffect(cgEnt) # calculate _scaleFactor and _anchorPt for viewPlacement, viewScale and billboarding attributes based on the bounding box of custom graphics entity maxPt = cgEnt.boundingBox.maxPoint minPt = cgEnt.boundingBox.minPoint _scaleFactor = 100 / minPt.distanceTo(maxPt) _anchorPt.setWithArray([(minPt.x + maxPt.x) / 2, (minPt.y + maxPt.y) / 2, (minPt.z + maxPt.z) / 2]) # view placement if _viewPlacementGroup and _viewPlacementGroup.isVisible and _viewPlacementGroup.isEnabledCheckBoxChecked and _viewCorner and _viewCorner.selectedItem: viewPt = adsk.core.Point2D.create(100,100) # upper left by default corner = adsk.fusion.ViewCorners.upperLeftViewCorner if _viewCorner.selectedItem.name == 'Upper Right': corner = adsk.fusion.ViewCorners.upperRightViewCorner elif _viewCorner.selectedItem.name == 'Lower Left': corner = adsk.fusion.ViewCorners.lowerLeftViewCorner elif _viewCorner.selectedItem.name == 'Lower Right': corner = adsk.fusion.ViewCorners.lowerRightViewCorner attr = adsk.fusion.CustomGraphicsViewPlacement.create(_anchorPt, corner, viewPt) cgEnt.viewPlacement = attr # view scale if _viewScaleGroup and _viewScaleGroup.isVisible and _viewScaleGroup.isEnabledCheckBoxChecked and _pixelScale: attr = adsk.fusion.CustomGraphicsViewScale.create(_scaleFactor * _pixelScale.valueOne, _anchorPt) cgEnt.viewScale = attr # billboarding if _billboardingGroup and _billboardingGroup.isVisible and _billboardingGroup.isEnabledCheckBoxChecked and _billboardingStyle and _billboardingStyle.selectedItem: # screen style by default bbStyle = adsk.fusion.CustomGraphicsBillBoardStyles.ScreenBillBoardStyle if _billboardingStyle.selectedItem.name == 'Axis': bbStyle = adsk.fusion.CustomGraphicsBillBoardStyles.AxialBillBoardStyle elif _billboardingStyle.selectedItem.name == 'Right Reading': bbStyle = adsk.fusion.CustomGraphicsBillBoardStyles.RightReadingBillBoardStyle attr = adsk.fusion.CustomGraphicsBillBoard.create(_anchorPt) attr.axis = adsk.core.Vector3D.create(0,1,0) attr.billBoardStyle = bbStyle cgEnt.billBoarding = attr except: if _ui: _ui.messageBox('Failed in MyCommandExecuteHandler:\n{}'.format(traceback.format_exc())) def changeCGObjVisibility(strObjName): try: _colorEffects.listItems.clear() _colorEffects.listItems.add(_colorEffect_solid_id, True) _colorEffects.listItems.add(_colorEffect_basicMaterial_id, False) _colorEffects.listItems.add(_colorEffect_appearance_id, False) _colorEffects.isVisible = False _selection.clearSelection() _selection.clearSelectionFilter() _selection.setSelectionLimits(0, 0) _selection.isVisible = False _selection.isEnabled = False _text.isVisible = False _coordTable.isVisible = False _isLineStrip.isVisible = False _lineStylePattern.isVisible = False _lineStyleWeight.isVisible = False _lineStyleScale.isVisible = False changeColorEffectVisibility(None) _viewPlacementGroup.isVisible = False _viewScaleGroup.isVisible = False _billboardingGroup.isVisible = False if strObjName == 'Mesh': _colorEffects.isVisible = True _colorEffects.listItems.add(_colorEffect_vertex_id, False) changeColorEffectVisibility(_colorEffect_solid_id) _viewPlacementGroup.isVisible = True _viewScaleGroup.isVisible = True _billboardingGroup.isVisible = True elif strObjName == 'Lines': changeColorEffectVisibility(_colorEffect_solid_id) _lineStylePattern.isVisible = True _lineStyleWeight.isVisible = True if _lineStylePattern.selectedItem.name != 'Solid Line': _lineStyleScale.isVisible = True _viewPlacementGroup.isVisible = True _viewScaleGroup.isVisible = True _billboardingGroup.isVisible = True elif strObjName == 'Curve': _selection.isVisible = True _selection.isEnabled = True _selection.tooltip = 'select a curve' _selection.commandPrompt = 'select a curve' _selection.addSelectionFilter('SketchCurves') _selection.setSelectionLimits(1,1) changeColorEffectVisibility(_colorEffect_solid_id) _lineStyleWeight.isVisible = True _viewPlacementGroup.isVisible = True _viewScaleGroup.isVisible = True _billboardingGroup.isVisible = True elif strObjName == 'BRep': _selection.isVisible = True _selection.isEnabled = True _selection.tooltip = 'select a body' _selection.commandPrompt = 'select a body' _selection.addSelectionFilter('Bodies') _selection.setSelectionLimits(1,1) _colorEffects.isVisible = True changeColorEffectVisibility(_colorEffect_solid_id) _viewPlacementGroup.isVisible = True _viewScaleGroup.isVisible = True _billboardingGroup.isVisible = True elif strObjName == 'Text': _text.isVisible = True _textSize.isVisible = True _textStyle.isVisible = True _textFont.isVisible = True elif strObjName == 'PointSet - Custom': _coordTable.isVisible = True _addStrip.isEnabled = False elif strObjName == 'Lines - Custom': _coordTable.isVisible = True _isLineStrip.isVisible = True _addStrip.isEnabled = True changeColorEffectVisibility(_colorEffect_solid_id) _lineStylePattern.isVisible = True _lineStyleWeight.isVisible = True if _lineStylePattern.selectedItem.name != 'Solid Line': _lineStyleScale.isVisible = True except: if _ui: _ui.messageBox('Failed in changeCGObjVisibility:\n{}'.format(traceback.format_exc())) def changeColorEffectVisibility(strColorEffectName): try: _red.isVisible = False _green.isVisible = False _blue.isVisible = False _opacity.isVisible = False _glossiness.isVisible = False _appearanceList.isVisible = False _materialLibList.isVisible = False _appearanceFilter.isVisible = False if strColorEffectName == _colorEffect_solid_id: _red.isVisible = True _green.isVisible = True _blue.isVisible = True elif strColorEffectName == _colorEffect_basicMaterial_id: _opacity.isVisible = True _glossiness.isVisible = True elif strColorEffectName == _colorEffect_appearance_id: _appearanceList.isVisible = True _materialLibList.isVisible = True _appearanceFilter.isVisible = True except: if _ui: _ui.messageBox('Failed in changeColorEffectVisibility:\n{}'.format(traceback.format_exc())) def changeLineStyleInputsVisibility(patternName): try: if patternName == 'Solid Line': _lineStyleScale.isVisible = False else: _lineStyleScale.isVisible = True except: if _ui: _ui.messageBox('Failed in changeLineStyleInputsVisibility:\n{}'.format(traceback.format_exc())) # Event handler for the inputChanged event. class MyCommandInputChangedHandler(adsk.core.InputChangedEventHandler): def __init__(self): super().__init__() def notify(self, args): try: eventArgs = adsk.core.InputChangedEventArgs.cast(args) changedInput = eventArgs.input if changedInput.id == _commandId + '_cgObj': changeCGObjVisibility(_customGraphicsObj.selectedItem.name) elif changedInput.id == _commandId + '_colorEffects': changeColorEffectVisibility(_colorEffects.selectedItem.name) elif changedInput.id == _commandId + '_appearanceFilter' or changedInput.id == _commandId + '_materialLib': appearances = getAppearancesFromLib(_materialLibList.selectedItem.name, _appearanceFilter.value) replaceItems(_appearanceList, appearances) elif changedInput.id == _coordTable.id + '_add': addRow(_coordTable) elif changedInput.id == _coordTable.id + '_addStrip': addLineStrip(_coordTable) elif changedInput.id == _coordTable.id + '_delete': if _coordTable.selectedRow == -1: _ui.messageBox('Select one row to delete') else: _coordTable.deleteRow(_coordTable.selectedRow) elif changedInput.id == _commandId + '_LSPattern': changeLineStyleInputsVisibility(_lineStylePattern.selectedItem.name) except: if _ui: _ui.messageBox('Failed in MyCommandInputChangedHandler:\n{}'.format(traceback.format_exc())) def rotate2D(rad, vec): try: x = vec[0] y = vec[1] return (x*math.cos(rad)-y*math.sin(rad), x*math.sin(rad)+y*math.cos(rad)) except: if _ui: _ui.messageBox('Failed in rotate2D:\n{}'.format(traceback.format_exc())) def calculateCoordinates(numTeeth): try: # holeDia < rootDia < pitchDia < outsideDia holeDia = 0.5 * 2.54 diametralPitch = 2 / 2.54 pitchDia = numTeeth / diametralPitch if (diametralPitch < (20 *(math.pi/180))-0.000001): dedendum = 1.157 / diametralPitch else: circularPitch = math.pi / diametralPitch if circularPitch >= 20: dedendum = 1.25 / diametralPitch else: dedendum = (1.2 / diametralPitch) + (.002 * 2.54) rootDia = pitchDia - (2 * dedendum) outsideDia = (numTeeth + 2) / diametralPitch rPts0 = [] # 2 * numTeeth for root hPts0 = [] # 2 * numTeeth for hole pPts0 = [] # 2 * numTeeth for pitch oPts0 = [] # 1 * numTeeth for outside rPts1 = [] # 2 * numTeeth for root with thickness hPts1 = [] # 2 * numTeeth for hole with thickness pPts1 = [] # 2 * numTeeth for pitch with thickness oPts1 = [] # 1 * numTeeth for outside with thickness vecRootRadi = [rootDia/2.0, 0] vecHoleRadi = [holeDia/2.0, 0] vecPitchRadi = [pitchDia/2.0, 0] vecOutRadi = [outsideDia/2.0, 0] unitRadian = math.pi / numTeeth vecCoords = [] vecColors = [] for i in range(0, 2 * numTeeth): x, y = rotate2D(unitRadian * (i - 0.5), vecRootRadi) rPts0.append(int(len(vecCoords) / 3)) rPts1.append(int(len(vecCoords) / 3) + 1) vecCoords.extend([x, y, 0, x, y, _thickness]) vecColors.extend([255,0,255,128, 255,0,255,128]) for i in range(0, 2 * numTeeth): x, y = rotate2D(unitRadian * (i - 0.5), vecHoleRadi) hPts0.append(int(len(vecCoords) / 3)) hPts1.append(int(len(vecCoords) / 3) + 1) vecCoords.extend([x, y, 0, x, y, _thickness]) vecColors.extend([255,0,0,128, 255,0,0,128]) for i in range(0, 2 * numTeeth): x, y = rotate2D(unitRadian * (i - 0.5), vecPitchRadi) pPts0.append(int(len(vecCoords) / 3)) pPts1.append(int(len(vecCoords) / 3) + 1) vecCoords.extend([x, y, 0, x, y, _thickness]) vecColors.extend([0,0,255,128, 0,0,255,128]) for i in range(0, numTeeth): x, y = rotate2D(unitRadian * i * 2 , vecOutRadi) oPts0.append(int(len(vecCoords) / 3)) oPts1.append(int(len(vecCoords) / 3) + 1) vecCoords.extend([x, y, 0, x, y, _thickness]) vecColors.extend([0,255,255,128, 0,255,255,128]) return (rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1, vecCoords, vecColors) except: if _ui: _ui.messageBox('Failed in calculateCoordinates:\n{}'.format(traceback.format_exc())) def calculateStripLen(numTeeth): try: vecStripLen = [] for i in range(0, numTeeth): vecStripLen.append(6) for i in range(0, 2 * numTeeth): vecStripLen.append(21) for i in range(0, numTeeth): vecStripLen.append(24) for i in range(0, 2 * numTeeth): vecStripLen.append(6) return vecStripLen except Exception as error: _ui.messageBox("calculateTriangles Failed : " + str(error)) def calculateTriangles(numTeeth, rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1): try: vertexIndexList = [] # triangles between teeth for i in range(0, numTeeth): idx0 = (2*i+1) % (2*numTeeth) idx1 = (2*i+2) % (2*numTeeth) rPtA0 = rPts0[idx0] rPtB0 = rPts0[idx1] rPtA1 = rPts1[idx0] rPtB1 = rPts1[idx1] vertexIndexList.extend([rPtA0,rPtB0,rPtB1, rPtB1,rPtA1,rPtA0]) # triangles on surface0 for i in range(0, numTeeth): rPtA = rPts0[i*2] rPtB = rPts0[i*2 + 1] rPtC = rPts0[(i*2 + 2)%(2*numTeeth)] hPtA = hPts0[i*2] hPtB = hPts0[i*2 + 1] hPtC = hPts0[(i*2 + 2)%(2*numTeeth)] pPtA = pPts0[i*2] pPtB = pPts0[i*2 + 1] oPt = oPts0[i] vertexIndexList.extend([hPtB,hPtC,rPtC, rPtC,rPtB,hPtB]) vertexIndexList.extend([rPtA,rPtB,pPtB, pPtB,pPtA,rPtA]) vertexIndexList.extend([hPtA,hPtB,rPtB, rPtB,rPtA,hPtA]) vertexIndexList.extend([pPtA,pPtB,oPt]) # triangles on surface1 for i in range(0, numTeeth): rPtA = rPts1[i*2] rPtB = rPts1[i*2 + 1] rPtC = rPts1[(i*2 + 2)%(2*numTeeth)] hPtA = hPts1[i*2] hPtB = hPts1[i*2 + 1] hPtC = hPts1[(i*2 + 2)%(2*numTeeth)] pPtA = pPts1[i*2] pPtB = pPts1[i*2 + 1] oPt = oPts1[i] vertexIndexList.extend([hPtC,hPtB,rPtB, rPtB,rPtC,hPtC]) vertexIndexList.extend([rPtB,rPtA,pPtA, pPtA,pPtB,rPtB]) vertexIndexList.extend([hPtB,hPtA,rPtA, rPtA,rPtB,hPtB]) vertexIndexList.extend([pPtB,pPtA,oPt]) # triangles on teeth for i in range(0, numTeeth): rPtA0 = rPts0[i*2] rPtB0 = rPts0[i*2 + 1] pPtA0 = pPts0[i*2] pPtB0 = pPts0[i*2 + 1] rPtA1 = rPts1[i*2] rPtB1 = rPts1[i*2 + 1] pPtA1 = pPts1[i*2] pPtB1 = pPts1[i*2 + 1] oPt0 = oPts0[i] oPt1 = oPts1[i] # triangles on one tooth vertexIndexList.extend([rPtA1, rPtA0, pPtA0, pPtA0, pPtA1, rPtA1]) vertexIndexList.extend([pPtA1, pPtA0, oPt0, oPt0, oPt1, pPtA1]) vertexIndexList.extend([rPtB0, rPtB1, pPtB1, pPtB1, pPtB0, rPtB0]) vertexIndexList.extend([pPtB0, pPtB1, oPt1, oPt1, oPt0, pPtB0]) # triangles on inner face for i in range(0, 2*numTeeth): hPtA0 = hPts0[i] hPtB0 = hPts0[(i + 1)%(2*numTeeth)] hPtA1 = hPts1[i] hPtB1 = hPts1[(i + 1)%(2*numTeeth)] vertexIndexList.extend([hPtA1,hPtB1,hPtB0, hPtB0,hPtA0,hPtA1]) return vertexIndexList except Exception as error: _ui.messageBox("calculateTriangles Failed : " + str(error)) return None # Builds a custom graphics mesh. def drawMesh(cgGroup): try: # Calculate mesh coordinates rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1, vecCoords, vecColors = calculateCoordinates(_numTeeth) coordinates = adsk.fusion.CustomGraphicsCoordinates.create(vecCoords) coordinates.colors = vecColors # Calculate mesh triangles vertexIndexList = calculateTriangles(_numTeeth, rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1) # Add Custom Graphics mesh normalVectors = [] normalIndexList = [] cgMesh = cgGroup.addMesh(coordinates, vertexIndexList, normalVectors, normalIndexList) return cgMesh except Exception as error: _ui.messageBox("drawMesh Failed : " + str(error)) return None def drawLines(cgGroup): try: rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1, vecCoords, vecColors = calculateCoordinates(_numTeeth) coordinates = adsk.fusion.CustomGraphicsCoordinates.create(vecCoords) vertexIndexList = calculateTriangles(_numTeeth, rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1) stripLen = calculateStripLen(_numTeeth) cgLines = cgGroup.addLines(coordinates, vertexIndexList, True, stripLen) return cgLines except Exception as error: _ui.messageBox("drawLines Failed : " + str(error)) return None def drawPointSet(cgGroup): try: rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1, vecCoords, vecColors = calculateCoordinates(_numTeeth) coordinates = adsk.fusion.CustomGraphicsCoordinates.create(vecCoords) cgPoints = cgGroup.addPointSet(coordinates, [], adsk.fusion.CustomGraphicsPointTypes.UserDefinedCustomGraphicsPointType, _pointSetImage) return cgPoints except Exception as error: _ui.messageBox("drawPointSet Failed : " + str(error)) return None