Skip to content

Commit 86c5529

Browse files
committed
Use FCStd class for jcad to freecad conversion
1 parent b843518 commit 86c5529

File tree

2 files changed

+74
-8
lines changed

2 files changed

+74
-8
lines changed
Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,38 @@
11
import freecad as fc
2+
import base64
3+
import tempfile
4+
from .loader import FCStd
5+
import os
6+
27

38
def convert_jcad_to_fcstd(jcad_dict: dict) -> 'fc.Document':
4-
"""
5-
Stub converter: create an empty FreeCAD document.
6-
Later, fill this in by iterating jcad_dict["objects"] and applying ops.
7-
"""
8-
doc = fc.app.newDocument("FromJCAD")
9-
# TODO: recreate primitives & boolean ops here
10-
return doc
9+
# 1) Spin up a brand‑new FreeCAD doc and write it out to a temp .FCStd
10+
blank = fc.app.newDocument("__jcad_blank__")
11+
blank.recompute() # ensure it's fully initialized
12+
with tempfile.NamedTemporaryFile(delete=False, suffix=".FCStd") as tmp_blank:
13+
blank.saveAs(tmp_blank.name)
14+
tmp_blank.flush()
15+
fc.app.closeDocument(blank.Name)
16+
17+
# 2) Read its bytes, encode as base64, give to FCStd loader
18+
with open(tmp_blank.name, "rb") as f:
19+
b64_blank = base64.b64encode(f.read()).decode("utf-8")
20+
os.remove(tmp_blank.name)
21+
22+
fcstd = FCStd()
23+
fcstd._sources = b64_blank
24+
25+
# 3) Replay your JCAD model into it
26+
objs = jcad_dict.get("objects", [])
27+
opts = jcad_dict.get("options", {})
28+
meta = jcad_dict.get("metadata", {})
29+
fcstd.save(objs, opts, meta)
30+
31+
# 4) Dump the new .FCStd and re‑open it
32+
with tempfile.NamedTemporaryFile(delete=False, suffix=".FCStd") as tmp_out:
33+
tmp_out.write(base64.b64decode(fcstd.sources))
34+
tmp_out.flush()
35+
36+
doc = fc.app.openDocument(tmp_out.name)
37+
return doc
38+

jupytercad_freecad/handlers.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import tornado
88

99
from jupytercad_freecad.freecad.loader import FCStd
10-
10+
from jupytercad_freecad.freecad.jcad_converter import convert_jcad_to_fcstd
1111

1212
class BackendCheckHandler(APIHandler):
1313
@tornado.web.authenticated
@@ -85,6 +85,40 @@ def post(self):
8585
self.finish(json.dumps({"done": True, "exportedPath": str(export_path)}))
8686

8787

88+
class FCStdExportHandler(APIHandler):
89+
@tornado.web.authenticated
90+
def post(self):
91+
body = self.get_json_body()
92+
93+
# same path‐splitting logic as JCadExportHandler
94+
path = body.get("path", "")
95+
parts = path.split(":", 1)
96+
file_name = parts[1] if len(parts) == 2 else parts[0]
97+
98+
new_name = body["newName"]
99+
root_dir = Path(self.contents_manager.root_dir).resolve()
100+
in_path = Path(to_os_path(ApiPath(file_name), str(root_dir)))
101+
out_path = in_path.parent / new_name
102+
103+
# load JCAD JSON from disk
104+
try:
105+
jcad_dict = json.loads(in_path.read_text())
106+
except Exception as e:
107+
self.log.error(f"Error reading JCAD file {in_path}: {e}")
108+
self.set_status(500)
109+
return self.finish(json.dumps({"error": str(e)}))
110+
111+
# convert to FreeCAD document
112+
try:
113+
doc = convert_jcad_to_fcstd(jcad_dict)
114+
doc.saveAs(str(out_path)) # write .FCStd
115+
except Exception as e:
116+
self.log.error(f"Conversion to FCStd failed: {e}")
117+
self.set_status(500)
118+
return self.finish(json.dumps({"error": str(e)}))
119+
120+
self.finish(json.dumps({"done": True, "exportedPath": str(out_path)}))
121+
88122
def setup_handlers(web_app):
89123
host_pattern = ".*$"
90124

@@ -98,6 +132,10 @@ def setup_handlers(web_app):
98132
(
99133
url_path_join(base_url, "jupytercad_freecad", "export-jcad"),
100134
JCadExportHandler,
135+
),
136+
(
137+
url_path_join(base_url, "jupytercad_freecad", "export-fcstd"),
138+
FCStdExportHandler,
101139
),
102140
]
103141
web_app.add_handlers(host_pattern, handlers)

0 commit comments

Comments
 (0)