forked from hlorus/CAD_Sketcher
-
Notifications
You must be signed in to change notification settings - Fork 0
/
serialize.py
161 lines (110 loc) · 4.23 KB
/
serialize.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import pickle
from typing import Union, Optional
from pathlib import Path
from bpy.types import Scene
from .utilities.index import breakdown_index, assemble_index
def dict_extend(original_dict, other):
"""Similar to native update() but extends values "+=" when key is in both dictionaries"""
for key, value in other.items():
if key in original_dict:
original_dict[key] += value
continue
original_dict[key] = value
# Format of scene dict:
# {
# 'entities': {
# 'points3D': [{}, {}],
# 'normals3D': [{}, {}],
# }
def scene_to_dict(scene):
original = scene["sketcher"].to_dict()
elements = {key: original[key] for key in ("entities", "constraints")}
return elements
def scene_from_dict(scene, elements):
original = scene["sketcher"].to_dict()
original.update(elements)
scene["sketcher"].update(original)
def _extend_element_dict(scene, elements):
"""Returns dictionary representation of scene with extended entities and constraints"""
scene_dict = scene_to_dict(scene)
fix_pointers(elements)
for key in ("entities", "constraints"):
dict_extend(scene_dict[key], elements[key])
return scene_dict
def fix_pointers(elements):
"""Go through all properties and offset entity pointers"""
import bpy
offsets = bpy.context.scene.sketcher.entities.collection_offsets()
indices = _get_indices(elements)
# Create pointer map {old_ptr: new_ptr,}
index_mapping = {}
for type_index, local_indices in indices.items():
offset = offsets[type_index]
for i in range(len(local_indices)):
old_index = local_indices[i]
if old_index in index_mapping.keys():
continue
index_mapping[assemble_index(type_index, old_index)] = assemble_index(
type_index, offset + i
)
_replace_indices(elements, index_mapping)
def iter_elements_dict(element_dict):
"""Iterate through every property in elements dictionary"""
for element_key in ("entities", "constraints"):
for element_coll, elems in element_dict[element_key].items():
if not isinstance(elems, list):
continue
for elem in elems:
yield elem
def _replace_indices(elements, mapping: dict):
"""Go through all indices and replace indices based on index mapping"""
for elem in iter_elements_dict(elements):
for prop in elem.keys():
if not prop.endswith("_i") and prop != "slvs_index":
continue
value = elem[prop]
if value not in mapping.keys():
continue
elem[prop] = mapping[value]
def _get_indices(elements):
"""Collect and sort slvs_index's of all entities"""
indices = {}
for elem in iter_elements_dict(elements):
if "slvs_index" not in elem.keys():
continue
slvs_index = elem["slvs_index"]
type_index, local_index = breakdown_index(slvs_index)
if local_index not in indices.setdefault(type_index, []):
indices[type_index].append(local_index)
[l.sort() for l in indices.values()]
return indices
def save(file: Union[str, Path], scene: Optional[Scene] = None):
"""Saves CAD Sketcher data of scene into file"""
if not scene:
import bpy
scene = bpy.context.scene
with open(file, "wb") as picklefile:
pickler = pickle.Pickler(picklefile)
# Convert to dict to avoid pickling PropertyGroup instances
dict = scene_to_dict(scene)
pickler.dump(dict)
picklefile.close()
def load(file: Union[str, Path], scene: Optional[Scene] = None):
"""Overwrites scene with entities and constraints stored in file"""
if not scene:
import bpy
scene = bpy.context.scene
with open(file, "rb") as picklefile:
unpickler = pickle.Unpickler(picklefile)
load_dict = unpickler.load()
scene_from_dict(scene, load_dict)
def paste(context, dictionary):
scene = context.scene
final_dict = _extend_element_dict(
scene,
{
"entities": dictionary["entities"],
"constraints": dictionary["constraints"],
},
)
scene_from_dict(scene, final_dict)