Skip to content

Commit 70c140a

Browse files
committed
Refactor code
1 parent 41f04d1 commit 70c140a

File tree

2 files changed

+50
-59
lines changed

2 files changed

+50
-59
lines changed

jupytercad_freecad/freecad/jcad_converter.py

Lines changed: 49 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ def create_body_and_coordinates(doc, body_obj, fc_objects):
5050
fc_objects["Origin"] = body_fc.Origin
5151
for child in body_fc.Origin.Group:
5252
role = getattr(child, "Role", "")
53-
# Role is typically "X_Axis", "Y_Axis", "Z_Axis", "XY_Plane", etc.
5453
if role in {"X_Axis", "Y_Axis", "Z_Axis", "XY_Plane", "XZ_Plane", "YZ_Plane"}:
5554
fc_objects[role] = child
5655

@@ -90,19 +89,20 @@ def export_jcad_to_fcstd(jcad_dict: dict) -> "fc.Document":
9089
"Origin", "X_Axis", "Y_Axis", "Z_Axis", "XY_Plane", "XZ_Plane", "YZ_Plane"
9190
}
9291

93-
# 1) Sanitize all JCAD object names and build a mapping
94-
name_mapping = {
95-
obj["name"]: sanitize_object_name(obj["name"])
96-
for obj in jcad_dict.get("objects", [])
97-
}
92+
# 1) Sanitize JCAD names in place and build a mapping
93+
name_mapping = {}
9894
for obj in jcad_dict.get("objects", []):
99-
obj["name"] = name_mapping[obj["name"]]
95+
original = obj["name"]
96+
sanitized = sanitize_object_name(original)
97+
name_mapping[original] = sanitized
98+
obj["name"] = sanitized
99+
100100
update_references(jcad_dict, name_mapping)
101101

102102
fc_objects = {}
103-
guidata = {} # objectName → { "ShapeColor": (r,g,b), "Visibility": bool }
103+
guidata = {}
104104

105-
# 2) Separate out any PartDesign::Body objects
105+
# 2) Separate PartDesign::Body entries from others
106106
body_objs = [
107107
o for o in jcad_dict.get("objects", [])
108108
if o["shape"] == "PartDesign::Body"
@@ -112,75 +112,68 @@ def export_jcad_to_fcstd(jcad_dict: dict) -> "fc.Document":
112112
if o not in body_objs and o["name"] not in coordinate_names
113113
]
114114

115-
# 3) Create bodies (so that coordinate system objects appear)
115+
# Helper: determine RGB tuple and visibility flag
116+
def _color_and_visibility(jcad_obj):
117+
opts = jcad_dict.get("options", {}).get(jcad_obj["name"], {})
118+
hexcol = (
119+
jcad_obj.get("parameters", {}).get("Color")
120+
or opts.get("color", "#808080")
121+
)
122+
rgb = _hex_to_rgb(hexcol)
123+
visible = opts.get("visible")
124+
if visible is None:
125+
visible = jcad_obj.get("visible", True)
126+
return rgb, visible
127+
128+
# 3) Create all PartDesign::Body objects
116129
for body_obj in body_objs:
117130
body_fc = create_body_and_coordinates(doc, body_obj, fc_objects)
118131
apply_object_properties(body_fc, body_obj, prop_handlers, doc)
119132

120-
# Record body color
121-
hexcol = body_obj.get("parameters", {}).get("Color") or \
122-
(jcad_dict.get("options", {}).get(body_obj["name"], {}).get("color") or "#808080")
123-
rgb = _hex_to_rgb(hexcol)
124-
125-
# Instead of just building color_map, build a complete guidata dictionary
126-
body_opts = jcad_dict.get("options", {}).get(body_obj["name"], {})
127-
# Check visibility: prioritize options, then object-level visible, default to True
128-
visible = body_opts.get("visible")
129-
if visible is None:
130-
visible = body_obj.get("visible", True)
131-
133+
rgb, visible = _color_and_visibility(body_obj)
132134
guidata[body_obj["name"]] = {
133135
"ShapeColor": {"type": "App::PropertyColor", "value": rgb},
134136
"Visibility": {"type": "App::PropertyBool", "value": visible},
135137
}
136138

137-
# Any coordinate‐system objects that now exist should inherit the same color
138-
for coord_name in coordinate_names:
139-
if coord_name in fc_objects:
140-
guidata[coord_name] = {
139+
# Coordinate children inherit the same color but remain hidden
140+
for coord in coordinate_names:
141+
if coord in fc_objects:
142+
guidata[coord] = {
141143
"ShapeColor": {"type": "App::PropertyColor", "value": rgb},
142-
"Visibility": {"type": "App::PropertyBool", "value": False}, # Usually coordinate objects are hidden
144+
"Visibility": {"type": "App::PropertyBool", "value": False},
143145
}
144146

145-
# 4) Create all other (non-body, non-coordinate) objects
147+
# 4) Create all other objects
146148
for obj in other_objs:
147149
fc_obj = doc.addObject(obj["shape"], obj["name"])
148150
fc_objects[obj["name"]] = fc_obj
149151
apply_object_properties(fc_obj, obj, prop_handlers, doc)
150152

151-
# Instead of just building color_map, build a complete guidata dictionary
152-
obj_opts = jcad_dict.get("options", {}).get(obj["name"], {})
153-
hexcol = obj.get("parameters", {}).get("Color") or obj_opts.get("color", "#808080")
154-
# Check visibility: prioritize options, then object-level visible, default to True
155-
visible = obj_opts.get("visible")
156-
if visible is None:
157-
visible = obj.get("visible", True)
158-
159-
# Build guidata entry with both color and visibility
153+
rgb, visible = _color_and_visibility(obj)
154+
default_camera = (
155+
"OrthographicCamera {\n"
156+
" viewportMapping ADJUST_CAMERA\n"
157+
" position 5.0 0.0 10.0\n"
158+
" orientation 0.7 0.2 0.4 1.0\n"
159+
" nearDistance 0.2\n"
160+
" farDistance 20.0\n"
161+
" aspectRatio 1.0\n"
162+
" focalDistance 8.0\n"
163+
" height 16.0\n"
164+
"}")
160165
guidata[obj["name"]] = {
161-
"ShapeColor": {"type": "App::PropertyColor", "value": _hex_to_rgb(hexcol)},
166+
"ShapeColor": {"type": "App::PropertyColor", "value": rgb},
162167
"Visibility": {"type": "App::PropertyBool", "value": visible},
163168
}
169+
guidata["GuiCameraSettings"] = default_camera
164170

165-
# 5) Recompute so that FreeCAD has generated any missing children
171+
# 5) Recompute so FreeCAD generates any missing children
166172
doc.recompute()
167173

168-
# 6) Save to a temp FCStd using guidata instead of colors
174+
# 7) Save with guidata so FreeCAD writes a full GuiDocument.xml
169175
with tempfile.NamedTemporaryFile(delete=False, suffix=".FCStd") as tmp:
170-
tmp_path = tmp.name
171-
172-
# Default camera settings
173-
default_camera = 'OrthographicCamera { viewportMapping ADJUST_CAMERA position 8.5470247 -1.1436439 9.9673195 orientation 0.86492187 0.23175442 0.44519675 1.0835806 nearDistance 0.19726367 farDistance 17.140171 aspectRatio 1 focalDistance 8.6602545 height 17.320509 }'
174-
175-
# Add camera to guidata - try the direct string approach
176-
guidata["GuiCameraSettings"] = default_camera
177-
178-
# Use guidata to include both color, visibility, AND camera
179-
OfflineRenderingUtils.save(
180-
doc,
181-
filename=tmp_path,
182-
guidata=guidata
183-
)
176+
path = tmp.name
177+
OfflineRenderingUtils.save(doc, filename=path, guidata=guidata)
184178

185-
# 7) Finally, open that new FCStd in FreeCAD and return the Document handle
186-
return fc.app.openDocument(tmp_path)
179+
return fc.app.openDocument(path)

jupytercad_freecad/freecad/props/property_partshape.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,13 @@ def jcad_to_fc(prop_value: str, **kwargs) -> Any:
3030

3131
try:
3232
shape = Part.Shape()
33-
# Use importBrepFromString as it's more specific for BREP strings
3433
shape.importBrepFromString(prop_value)
3534

3635
if shape.isNull():
3736
print(f"Warning: Reconstructed shape is Null after importBrepFromString. Input (first 100 chars): {prop_value[:100]}...")
38-
return None # Return None if shape is Null
37+
return None
3938

4039
return shape
4140
except Exception as e:
42-
# Log the actual exception and part of the problematic string
4341
print(f"Failed to rebuild BRep shape with importBrepFromString: {e}. Input (first 100 chars): {prop_value[:100]}...")
4442
return None

0 commit comments

Comments
 (0)