Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a2f99d3
feat: adding design check tab to exporter
Dhruv-0-Arora Jul 8, 2025
066e38c
feat: adding height and perimeter rule checks
Dhruv-0-Arora Jul 14, 2025
4fa43c8
feat: adding DRC UI
Dhruv-0-Arora Jul 14, 2025
a968146
Merging Dev
Dhruv-0-Arora Jul 18, 2025
5021b5b
fix: formatting and mypy
Dhruv-0-Arora Jul 18, 2025
cecb5d9
formatting
Dhruv-0-Arora Jul 18, 2025
fbd2574
Merge branch 'dev' into dhruv/1882/drc-ui-support
Dhruv-0-Arora Jul 18, 2025
b0df31b
feat: adding table with icons showing validity
Dhruv-0-Arora Jul 18, 2025
fe3e116
Merging Local
Dhruv-0-Arora Jul 18, 2025
6d2e608
feat: adding invalid and proper perimeter validation
Dhruv-0-Arora Jul 18, 2025
140645b
formatting
Dhruv-0-Arora Jul 18, 2025
c8d5c60
Merge branch 'dev' into dhruv/1882/drc-ui-support
PepperLola Jul 19, 2025
5e46d91
fix: removing orientedboundingbox
Dhruv-0-Arora Jul 23, 2025
00b1242
Merging Dev
Dhruv-0-Arora Jul 23, 2025
9130b8a
feat: adding extensibility
Dhruv-0-Arora Jul 23, 2025
1a5eb20
fix: formatting
Dhruv-0-Arora Jul 23, 2025
5ad15c1
fix: mypy
Dhruv-0-Arora Jul 23, 2025
1cb1f5c
feat: typing and resolving mypy
Dhruv-0-Arora Jul 24, 2025
6aee78b
feat: changing calculations using different orientations of the bound…
Dhruv-0-Arora Jul 24, 2025
134b42f
Merging Dev and Formatting
Dhruv-0-Arora Jul 25, 2025
e031d0b
Merging Dev
Dhruv-0-Arora Jul 30, 2025
e9e3f49
feat: adding web tab
Dhruv-0-Arora Jul 30, 2025
fe2327f
feat: sending designRuleChecks to web-based UI
Dhruv-0-Arora Aug 1, 2025
efcfde1
feat: adding json dumps and fixing callable functions
Dhruv-0-Arora Aug 4, 2025
f43d4e5
merging dev
Dhruv-0-Arora Aug 6, 2025
b05fd8e
fix: conflicts
Dhruv-0-Arora Aug 6, 2025
77f852b
fix: table not displaying on tab
Dhruv-0-Arora Aug 7, 2025
af430a8
feat: adding validation header
Dhruv-0-Arora Aug 7, 2025
0fe4a98
fix: biome errors and formatting
Dhruv-0-Arora Aug 7, 2025
01abb79
fix: sendData run when window is undefined
Dhruv-0-Arora Aug 19, 2025
8d4b88d
Merge branch 'dev' into dhruv/1882/drc-ui-support
Dhruv-0-Arora Aug 19, 2025
9fd087d
fix: removing redundant state implementation
Dhruv-0-Arora Aug 20, 2025
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
49 changes: 49 additions & 0 deletions exporter/SynthesisFusionAddin/src/DesignRuleChecks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from typing import List, TypedDict, Callable

import adsk.core
import adsk.fusion

from src import Logging, gm

class DesignRule(TypedDict):
name: str
calculation: Callable[[], float]
max_value: float

class DesignRuleChecks:
designRules: List[DesignRule]

@Logging.logFailure
def __init__(self) -> None:
self.designRules = [
{
"name": "Design Height",
"calculation": self.fusion_design_height,
"max_value": 106.0, # cm
},
{
"name": "Design Perimeter",
"calculation": self.fusion_design_perimeter,
"max_value": 304.0, # cm
},
]


def getDesignRules(self) -> List[DesignRule]:
return self.designRules

@Logging.logFailure
def fusion_design_height(self) -> float:
design = adsk.fusion.Design.cast(gm.app.activeProduct)
if design:
overall_bounding_box = design.rootComponent.orientedMinimumBoundingBox
return float(overall_bounding_box.width)
return 0.0

@Logging.logFailure
def fusion_design_perimeter(self) -> float:
design = adsk.fusion.Design.cast(gm.app.activeProduct)
if design:
overall_bounding_box = design.rootComponent.orientedMinimumBoundingBox
return float(2 * (overall_bounding_box.height + overall_bounding_box.length))
return 0.0
4 changes: 4 additions & 0 deletions exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from src.Types import SELECTABLE_JOINT_TYPES, ExportLocation, ExportMode
from src.UI import FileDialogConfig
from src.UI.Handlers import PersistentEventHandler
from src.DesignRuleChecks import DesignRuleChecks
from src.Util import convertMassUnitsTo, designMassCalculation

generalConfigTab: GeneralConfigTab.GeneralConfigTab
Expand Down Expand Up @@ -299,6 +300,9 @@ def notify(self, html_args: adsk.core.HTMLEventArgs) -> None:
elif html_args.action == "cancelSelection":
gm.ui.terminateActiveCommand()
html_args.returnData = "{}"

elif html_args.action == "designRules":
html_args.returnData = DesignRuleChecks().getDesignRules
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be dumped as json

else:
gm.ui.messageBox(f"Event {html_args.action} arrived<span>{json.dumps(data, indent=2)}</span>")

Expand Down
44 changes: 5 additions & 39 deletions exporter/SynthesisFusionAddin/src/UI/DesignCheckTab.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,17 @@
import adsk.core
import adsk.fusion

from src import Logging, gm
from src import Logging
from src.UI import IconPaths
from src.DesignRuleChecks import DesignRuleChecks

logger = Logging.getLogger()


class DesignRule(TypedDict):
name: str
calculation: Callable[[], float]
max_value: float


class DesignCheckTab:
designCheckTab: adsk.core.TabCommandInput
designCheckTable: adsk.core.TableCommandInput
designRules: Dict[str, Any] = {}
design_rules: List[DesignRule]
designRuleChecks: DesignRuleChecks

@Logging.logFailure
def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None:
Expand All @@ -34,21 +28,9 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None:
adsk.core.TablePresentationStyles.itemBorderTablePresentationStyle
)

# Define and add design rules to the table
self.design_rules = [
{
"name": "Design Height",
"calculation": self.fusion_design_height,
"max_value": 106.0, # cm
},
{
"name": "Design Perimeter",
"calculation": self.fusion_design_perimeter,
"max_value": 304.0, # cm
},
]
self.designRuleChecks = DesignRuleChecks()

for i, rule in enumerate(self.design_rules):
for i, rule in enumerate(self.designRuleChecks.getDesignRules()):
calculation = rule["calculation"]
max_value: float = rule["max_value"]
value: float = calculation()
Expand Down Expand Up @@ -81,19 +63,3 @@ def isVisible(self, value: bool) -> None:
@property
def isActive(self) -> bool:
return self.designCheckTab.isActive or False

@Logging.logFailure
def fusion_design_height(self) -> float:
design = adsk.fusion.Design.cast(gm.app.activeProduct)
if design:
overall_bounding_box = design.rootComponent.orientedMinimumBoundingBox
return float(overall_bounding_box.width)
return 0.0

@Logging.logFailure
def fusion_design_perimeter(self) -> float:
design = adsk.fusion.Design.cast(gm.app.activeProduct)
if design:
overall_bounding_box = design.rootComponent.orientedMinimumBoundingBox
return float(2 * (overall_bounding_box.height + overall_bounding_box.length))
return 0.0
7 changes: 6 additions & 1 deletion exporter/SynthesisFusionAddin/web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useState } from "react"

import "./App.css"
import { RestartAlt, Settings, SportsFootball, Texture } from "@mui/icons-material"
import { RestartAlt, Settings, SportsFootball, Texture, CheckBox } from "@mui/icons-material"
import DownloadIcon from "@mui/icons-material/Download"
import PrecisionManufacturingIcon from "@mui/icons-material/PrecisionManufacturing"
import SaveIcon from "@mui/icons-material/Save"
Expand Down Expand Up @@ -37,6 +37,7 @@ import GeneralConfigTab from "./ui/GeneralConfigTab.tsx"
import GlobalAlert from "./ui/GlobalAlert.tsx"
import JointsConfigTab from "./ui/JointsConfigTab.tsx"
import MaterialTaggingTab, { type TaggedBody } from "./ui/MaterialTaggingTab.tsx"
import DesignCheckTab from "./ui/DesignCheckTab.tsx"

function TabPanel(props: { children?: React.ReactNode; value: number; index: number }) {
const { children, value, index, ...other } = props
Expand Down Expand Up @@ -228,6 +229,7 @@ function App() {
/>

<Tab icon={<Texture />} iconPosition={"start"} label="Materials" />
<Tab icon={<CheckBox />} iconPosition={"start"} label="Design Check" />

{/*<Tab label="APS" />*/}
</Tabs>
Expand Down Expand Up @@ -259,6 +261,9 @@ function App() {
selection={{ isSelecting, setIsSelecting }}
/>
</TabPanel>
<TabPanel value={activeTab} index={2}>
<DesignCheckTab />
</TabPanel>
<Container
sx={{
position: "sticky",
Expand Down
26 changes: 26 additions & 0 deletions exporter/SynthesisFusionAddin/web/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
selectJoint: [Empty, FusionJoint]
selectGamepiece: [Empty, FusionGamepiece[]]
selectBody: [Empty, FusionBody]
designRules: [Empty, DesignRule[]]
export: [ExporterConfig, Empty]
save: [ExporterConfig, Empty]
init: [Empty, InitResponse]
Expand Down Expand Up @@ -146,3 +147,28 @@
return "OK"
},
}

export interface DesignRule {
name: string,
calculation: number,
max_value: number
}
export async function getDesignRules(): Promise<DesignRule[] | undefined> {
if (import.meta.env.DEV && typeof window.adsk === "undefined") {
return new Promise<DesignRule[]>(resolve => {
setTimeout(() => {
const token = Math.random().toString(36).substring(2, 15)

Check warning on line 160 in exporter/SynthesisFusionAddin/web/src/lib/index.ts

View check run for this annotation

Autodesk Chorus / security/semgrep

app.chorus.semgrep.rules.njsscan.crypto.node_insecure_random_generator

crypto.pseudoRandomBytes()/Math.random() is a cryptographically weak random number generator.

Check warning on line 160 in exporter/SynthesisFusionAddin/web/src/lib/index.ts

View check run for this annotation

Autodesk Chorus / security/semgrep

app.chorus.semgrep.rules.njsscan.semantic_grep.crypto.node_insecure_random_generator

crypto.pseudoRandomBytes()/Math.random() is a cryptographically weak random number generator.
resolve([
{
name: token,
calculation: parseFloat(token),
max_value: parseFloat(token)
}
])
}, 2000)
})
}

return await sendData("designRules", {})
}

67 changes: 45 additions & 22 deletions exporter/SynthesisFusionAddin/web/src/ui/DesignCheckTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,55 @@ import {
TableHead,
TableRow,
} from "@mui/material"
import { useEffect, useState } from "react"
import { type DesignRule, getDesignRules } from "../lib"

interface DesignCheckTabProps { }
interface DesignCheckTabProps {}

function DesignCheckTab({}: DesignCheckTabProps) {
return (
<TableContainer component={Paper} elevation={6}>
<Table sx={{ minWidth: 650 }} aria-label="simple table" size={"small"}>
<TableHead>
<TableRow>
<TableCell sx={{ width: "28%" }} align="center">
Component
</TableCell>
<TableCell sx={{ width: "28%" }} align="center">
Calculation
</TableCell>
<TableCell sx={{ width: "40%" }} align="center">
Is Valid
</TableCell>
<TableCell sx={{ width: "4%" }}></TableCell>
</TableRow>
</TableHead>
<TableBody>
const [rules, setRules] = useState<DesignRule[]>([])

useEffect(() => {
getDesignRules().then(data => {
if (data) {
setRules(data)
}
})
}, [])

</TableBody>
</Table>
</TableContainer>
return (
<>
<TableContainer component={Paper} elevation={6}>
<Table sx={{ minWidth: 650 }} aria-label="simple table" size={"small"}>
<TableHead>
<TableRow>
<TableCell sx={{ width: "28%" }} align="center">
Component
</TableCell>
<TableCell sx={{ width: "28%" }} align="center">
Calculation
</TableCell>
<TableCell sx={{ width: "40%" }} align="center">
Is Valid
</TableCell>
<TableCell sx={{ width: "4%" }}></TableCell>
</TableRow>
</TableHead>
<TableBody>
{rules.map(rule => (
<TableRow key={rule.name} sx={{ "&:last-child td, &:last-child th": { border: 0 } }}>
<TableCell align="center">{rule.name}</TableCell>
<TableCell align="center">{rule.calculation}</TableCell>
<TableCell align="center">
{rule.calculation <= rule.max_value ? "Valid" : "Invalid"}
</TableCell>
<TableCell />
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
)
}

Expand Down
Loading