Skip to content

Commit fe2327f

Browse files
committed
feat: sending designRuleChecks to web-based UI
1 parent e9e3f49 commit fe2327f

File tree

6 files changed

+135
-62
lines changed

6 files changed

+135
-62
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from typing import List, TypedDict, Callable
2+
3+
import adsk.core
4+
import adsk.fusion
5+
6+
from src import Logging, gm
7+
8+
class DesignRule(TypedDict):
9+
name: str
10+
calculation: Callable[[], float]
11+
max_value: float
12+
13+
class DesignRuleChecks:
14+
designRules: List[DesignRule]
15+
16+
@Logging.logFailure
17+
def __init__(self) -> None:
18+
self.designRules = [
19+
{
20+
"name": "Design Height",
21+
"calculation": self.fusion_design_height,
22+
"max_value": 106.0, # cm
23+
},
24+
{
25+
"name": "Design Perimeter",
26+
"calculation": self.fusion_design_perimeter,
27+
"max_value": 304.0, # cm
28+
},
29+
]
30+
31+
32+
def getDesignRules(self) -> List[DesignRule]:
33+
return self.designRules
34+
35+
@Logging.logFailure
36+
def fusion_design_height(self) -> float:
37+
design = adsk.fusion.Design.cast(gm.app.activeProduct)
38+
if design:
39+
overall_bounding_box = design.rootComponent.orientedMinimumBoundingBox
40+
return float(overall_bounding_box.width)
41+
return 0.0
42+
43+
@Logging.logFailure
44+
def fusion_design_perimeter(self) -> float:
45+
design = adsk.fusion.Design.cast(gm.app.activeProduct)
46+
if design:
47+
overall_bounding_box = design.rootComponent.orientedMinimumBoundingBox
48+
return float(2 * (overall_bounding_box.height + overall_bounding_box.length))
49+
return 0.0

exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from src.Types import SELECTABLE_JOINT_TYPES, ExportLocation, ExportMode
2929
from src.UI import FileDialogConfig
3030
from src.UI.Handlers import PersistentEventHandler
31+
from src.DesignRuleChecks import DesignRuleChecks
3132
from src.Util import convertMassUnitsTo, designMassCalculation
3233

3334
generalConfigTab: GeneralConfigTab.GeneralConfigTab
@@ -299,6 +300,9 @@ def notify(self, html_args: adsk.core.HTMLEventArgs) -> None:
299300
elif html_args.action == "cancelSelection":
300301
gm.ui.terminateActiveCommand()
301302
html_args.returnData = "{}"
303+
304+
elif html_args.action == "designRules":
305+
html_args.returnData = DesignRuleChecks().getDesignRules
302306
else:
303307
gm.ui.messageBox(f"Event {html_args.action} arrived<span>{json.dumps(data, indent=2)}</span>")
304308

exporter/SynthesisFusionAddin/src/UI/DesignCheckTab.py

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,17 @@
33
import adsk.core
44
import adsk.fusion
55

6-
from src import Logging, gm
6+
from src import Logging
77
from src.UI import IconPaths
8+
from src.DesignRuleChecks import DesignRuleChecks
89

910
logger = Logging.getLogger()
1011

1112

12-
class DesignRule(TypedDict):
13-
name: str
14-
calculation: Callable[[], float]
15-
max_value: float
16-
17-
1813
class DesignCheckTab:
1914
designCheckTab: adsk.core.TabCommandInput
2015
designCheckTable: adsk.core.TableCommandInput
21-
designRules: Dict[str, Any] = {}
22-
design_rules: List[DesignRule]
16+
designRuleChecks: DesignRuleChecks
2317

2418
@Logging.logFailure
2519
def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None:
@@ -34,21 +28,9 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None:
3428
adsk.core.TablePresentationStyles.itemBorderTablePresentationStyle
3529
)
3630

37-
# Define and add design rules to the table
38-
self.design_rules = [
39-
{
40-
"name": "Design Height",
41-
"calculation": self.fusion_design_height,
42-
"max_value": 106.0, # cm
43-
},
44-
{
45-
"name": "Design Perimeter",
46-
"calculation": self.fusion_design_perimeter,
47-
"max_value": 304.0, # cm
48-
},
49-
]
31+
self.designRuleChecks = DesignRuleChecks()
5032

51-
for i, rule in enumerate(self.design_rules):
33+
for i, rule in enumerate(self.designRuleChecks.getDesignRules()):
5234
calculation = rule["calculation"]
5335
max_value: float = rule["max_value"]
5436
value: float = calculation()
@@ -81,19 +63,3 @@ def isVisible(self, value: bool) -> None:
8163
@property
8264
def isActive(self) -> bool:
8365
return self.designCheckTab.isActive or False
84-
85-
@Logging.logFailure
86-
def fusion_design_height(self) -> float:
87-
design = adsk.fusion.Design.cast(gm.app.activeProduct)
88-
if design:
89-
overall_bounding_box = design.rootComponent.orientedMinimumBoundingBox
90-
return float(overall_bounding_box.width)
91-
return 0.0
92-
93-
@Logging.logFailure
94-
def fusion_design_perimeter(self) -> float:
95-
design = adsk.fusion.Design.cast(gm.app.activeProduct)
96-
if design:
97-
overall_bounding_box = design.rootComponent.orientedMinimumBoundingBox
98-
return float(2 * (overall_bounding_box.height + overall_bounding_box.length))
99-
return 0.0

exporter/SynthesisFusionAddin/web/src/App.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useCallback, useEffect, useState } from "react"
22

33
import "./App.css"
4-
import { RestartAlt, Settings, SportsFootball, Texture } from "@mui/icons-material"
4+
import { RestartAlt, Settings, SportsFootball, Texture, CheckBox } from "@mui/icons-material"
55
import DownloadIcon from "@mui/icons-material/Download"
66
import PrecisionManufacturingIcon from "@mui/icons-material/PrecisionManufacturing"
77
import SaveIcon from "@mui/icons-material/Save"
@@ -37,6 +37,7 @@ import GeneralConfigTab from "./ui/GeneralConfigTab.tsx"
3737
import GlobalAlert from "./ui/GlobalAlert.tsx"
3838
import JointsConfigTab from "./ui/JointsConfigTab.tsx"
3939
import MaterialTaggingTab, { type TaggedBody } from "./ui/MaterialTaggingTab.tsx"
40+
import DesignCheckTab from "./ui/DesignCheckTab.tsx"
4041

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

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

232234
{/*<Tab label="APS" />*/}
233235
</Tabs>
@@ -259,6 +261,9 @@ function App() {
259261
selection={{ isSelecting, setIsSelecting }}
260262
/>
261263
</TabPanel>
264+
<TabPanel value={activeTab} index={2}>
265+
<DesignCheckTab />
266+
</TabPanel>
262267
<Container
263268
sx={{
264269
position: "sticky",

exporter/SynthesisFusionAddin/web/src/lib/index.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ interface Messages {
2828
selectJoint: [Empty, FusionJoint]
2929
selectGamepiece: [Empty, FusionGamepiece[]]
3030
selectBody: [Empty, FusionBody]
31+
designRules: [Empty, DesignRule[]]
3132
export: [ExporterConfig, Empty]
3233
save: [ExporterConfig, Empty]
3334
init: [Empty, InitResponse]
@@ -146,3 +147,28 @@ window.fusionJavaScriptHandler = {
146147
return "OK"
147148
},
148149
}
150+
151+
export interface DesignRule {
152+
name: string,
153+
calculation: number,
154+
max_value: number
155+
}
156+
export async function getDesignRules(): Promise<DesignRule[] | undefined> {
157+
if (import.meta.env.DEV && typeof window.adsk === "undefined") {
158+
return new Promise<DesignRule[]>(resolve => {
159+
setTimeout(() => {
160+
const token = Math.random().toString(36).substring(2, 15)
161+
resolve([
162+
{
163+
name: token,
164+
calculation: parseFloat(token),
165+
max_value: parseFloat(token)
166+
}
167+
])
168+
}, 2000)
169+
})
170+
}
171+
172+
return await sendData("designRules", {})
173+
}
174+

exporter/SynthesisFusionAddin/web/src/ui/DesignCheckTab.tsx

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,55 @@ import {
77
TableHead,
88
TableRow,
99
} from "@mui/material"
10+
import { useEffect, useState } from "react"
11+
import { type DesignRule, getDesignRules } from "../lib"
1012

11-
interface DesignCheckTabProps { }
13+
interface DesignCheckTabProps {}
1214

1315
function DesignCheckTab({}: DesignCheckTabProps) {
14-
return (
15-
<TableContainer component={Paper} elevation={6}>
16-
<Table sx={{ minWidth: 650 }} aria-label="simple table" size={"small"}>
17-
<TableHead>
18-
<TableRow>
19-
<TableCell sx={{ width: "28%" }} align="center">
20-
Component
21-
</TableCell>
22-
<TableCell sx={{ width: "28%" }} align="center">
23-
Calculation
24-
</TableCell>
25-
<TableCell sx={{ width: "40%" }} align="center">
26-
Is Valid
27-
</TableCell>
28-
<TableCell sx={{ width: "4%" }}></TableCell>
29-
</TableRow>
30-
</TableHead>
31-
<TableBody>
16+
const [rules, setRules] = useState<DesignRule[]>([])
17+
18+
useEffect(() => {
19+
getDesignRules().then(data => {
20+
if (data) {
21+
setRules(data)
22+
}
23+
})
24+
}, [])
3225

33-
</TableBody>
34-
</Table>
35-
</TableContainer>
26+
return (
27+
<>
28+
<TableContainer component={Paper} elevation={6}>
29+
<Table sx={{ minWidth: 650 }} aria-label="simple table" size={"small"}>
30+
<TableHead>
31+
<TableRow>
32+
<TableCell sx={{ width: "28%" }} align="center">
33+
Component
34+
</TableCell>
35+
<TableCell sx={{ width: "28%" }} align="center">
36+
Calculation
37+
</TableCell>
38+
<TableCell sx={{ width: "40%" }} align="center">
39+
Is Valid
40+
</TableCell>
41+
<TableCell sx={{ width: "4%" }}></TableCell>
42+
</TableRow>
43+
</TableHead>
44+
<TableBody>
45+
{rules.map(rule => (
46+
<TableRow key={rule.name} sx={{ "&:last-child td, &:last-child th": { border: 0 } }}>
47+
<TableCell align="center">{rule.name}</TableCell>
48+
<TableCell align="center">{rule.calculation}</TableCell>
49+
<TableCell align="center">
50+
{rule.calculation <= rule.max_value ? "Valid" : "Invalid"}
51+
</TableCell>
52+
<TableCell />
53+
</TableRow>
54+
))}
55+
</TableBody>
56+
</Table>
57+
</TableContainer>
58+
</>
3659
)
3760
}
3861

0 commit comments

Comments
 (0)