1use std::{
16 collections::{BTreeMap, HashMap},
17 rc::Rc,
18};
19
20use geop_core_math::{
21 geop_error::{GeopError, GeopResult},
22 primitives::{CoordinateSystem, DatumComponent, DatumKind, Pose},
23 scalars::Scalar,
24 vector::{Vector, Vector3},
25};
26use geop_core_program::{
27 kept::Pool,
28 workspace::{base64, from_base64},
29};
30use serde::{Deserialize, Serialize};
31
32use super::{
33 FaceMesh, PartView, ViewAnnotation, ViewDatum, ViewEdge, ViewFace, ViewInstance, ViewVertex,
34};
35use crate::editing::Extent;
36
37#[derive(Serialize, Deserialize)]
39struct Written {
40 model: String,
41 vertices: Vec<Vertex>,
42 edges: Vec<Edge>,
43 faces: Vec<Face>,
44 datum_target: String,
45 datums: Vec<Datum>,
46 annotations: Vec<Annotation>,
47 solids: Vec<String>,
48 instances: Vec<Instance>,
49 #[serde(with = "geop_core_math::exact")]
50 center: Vector3,
51 #[serde(with = "geop_core_math::exact")]
52 size: Scalar,
53 color: Option<String>,
54 face_colors: BTreeMap<String, String>,
55}
56
57#[derive(Serialize, Deserialize)]
58struct Vertex {
59 name: String,
60 solid: Option<String>,
61 faces: Vec<String>,
62 #[serde(with = "geop_core_math::exact")]
63 at: Vector3,
64}
65
66#[derive(Serialize, Deserialize)]
67struct Edge {
68 name: String,
69 solid: Option<String>,
70 faces: Vec<String>,
71 #[serde(with = "geop_core_math::exact")]
72 polyline: Vec<Vector3>,
73 #[serde(default)]
74 within_a_surface: bool,
75 ends: [String; 2],
76}
77
78#[derive(Serialize, Deserialize)]
80struct Face {
81 name: String,
82 #[serde(default)]
83 also: Vec<String>,
84 solid: Option<String>,
85 feature: Option<String>,
86 mesh: String,
87}
88
89#[derive(Serialize, Deserialize)]
95struct Mesh {
96 key: String,
97 corners: String,
98 triangles: String,
99}
100
101impl Mesh {
102 fn of(mesh: &FaceMesh) -> GeopResult<Self> {
103 let mut index: HashMap<[u64; 6], u32> = HashMap::new();
104 let (mut corners, mut triangles) = (Vec::new(), Vec::new());
105 for (points, normals) in mesh.triangles.iter().zip(&mesh.normals) {
106 for (p, n) in points.iter().zip(normals) {
107 let mut bits = [0; 6];
108 let numbers = p.to_array().into_iter().chain(n.to_array());
109 for (bit, x) in bits.iter_mut().zip(numbers) {
110 if x.lo.to_bits() != x.hi.to_bits() {
111 return Err(GeopError::new("a mesh with a corner not sharp is not kept"));
112 }
113 *bit = x.lo.to_bits();
114 }
115 let next = index.len() as u32;
116 let at = *index.entry(bits).or_insert_with(|| {
117 corners.extend(bits.iter().flat_map(|b| b.to_le_bytes()));
118 next
119 });
120 triangles.extend(at.to_le_bytes());
121 }
122 }
123 Ok(Self {
124 key: mesh.key.clone(),
125 corners: base64(&corners),
126 triangles: base64(&triangles),
127 })
128 }
129
130 fn mesh(self) -> GeopResult<FaceMesh> {
131 let corner_bytes = from_base64(&self.corners)?;
132 let corners: Vec<[Scalar; 6]> = (corner_bytes.as_chunks::<48>().0.iter())
133 .map(|corner| {
134 std::array::from_fn(|k| {
135 let bytes = corner.get(8 * k..8 * k + 8).unwrap_or_default();
136 let bits = u64::from_le_bytes(bytes.try_into().unwrap_or_default());
137 Scalar::from_f64(f64::from_bits(bits))
138 })
139 })
140 .collect();
141 let corner = |bytes: &[u8]| -> GeopResult<&[Scalar; 6]> {
142 let at = u32::from_le_bytes(bytes.try_into().unwrap_or_default());
143 (corners.get(at as usize)).ok_or_else(|| broken("a mesh's corners"))
144 };
145 let (mut triangles, mut normals) = (Vec::new(), Vec::new());
146 let triangle_bytes = from_base64(&self.triangles)?;
147 for triangle in triangle_bytes.as_chunks::<12>().0 {
148 let [a, b, c] = [0, 4, 8].map(|k| corner(triangle.get(k..k + 4).unwrap_or_default()));
149 let [a, b, c] = [a?, b?, c?];
150 let point = |c: &[Scalar; 6]| Vector3::from_array([c[0], c[1], c[2]]);
151 let normal = |c: &[Scalar; 6]| Vector3::from_array([c[3], c[4], c[5]]);
152 triangles.push([point(a), point(b), point(c)]);
153 normals.push([normal(a), normal(b), normal(c)]);
154 }
155 Ok(FaceMesh {
156 key: self.key,
157 triangles,
158 normals,
159 })
160 }
161}
162
163#[derive(Serialize, Deserialize)]
164struct Datum {
165 name: String,
166 kind: DatumKind,
167 #[serde(with = "geop_core_math::exact")]
168 frame: CoordinateSystem,
169 components: Vec<(DatumComponent, String)>,
170}
171
172#[derive(Serialize, Deserialize)]
173struct Annotation {
174 name: String,
175 label: String,
176 #[serde(with = "geop_core_math::exact")]
177 polyline: Vec<Vector3>,
178}
179
180#[derive(Serialize, Deserialize)]
182struct Instance {
183 name: String,
184 component: String,
185 #[serde(with = "geop_core_math::exact")]
186 pose: Pose,
187 view: String,
188 state: Option<String>,
189 fixed: bool,
190}
191
192pub fn write(view: &PartView, pool: &mut Pool) -> GeopResult<String> {
195 text(&written(view, pool, &mut HashMap::new())?)
196}
197
198pub fn read(text: &str, pool: &Pool) -> GeopResult<PartView> {
200 let written: Written = serde_json::from_str(text)
201 .map_err(|e| GeopError::new(format!("reading a kept view: {e}")))?;
202 view_of(written, pool, &mut HashMap::new())
203}
204
205pub fn put(view: &PartView, pool: &mut Pool) -> GeopResult<String> {
208 let written = written(view, pool, &mut HashMap::new())?;
209 pool.put(&written)
210}
211
212pub fn get(key: &str, pool: &Pool) -> GeopResult<Rc<PartView>> {
215 pool.shared(key, || view_of(pool.get(key)?, pool, &mut HashMap::new()))
216}
217
218fn text<T: Serialize>(value: &T) -> GeopResult<String> {
219 serde_json::to_string(value).map_err(|e| GeopError::new(format!("writing a kept view: {e}")))
220}
221
222fn written(
225 view: &PartView,
226 pool: &mut Pool,
227 placed: &mut HashMap<*const PartView, String>,
228) -> GeopResult<Written> {
229 if !view.sketches.is_empty() {
230 return Err(GeopError::new(
231 "a view with sketches is not kept: its sketches are drawn again",
232 ));
233 }
234 let faces = (view.faces.iter())
235 .map(|face| {
236 Ok(Face {
237 also: face.also.clone(),
238 name: face.name.clone(),
239 solid: face.solid.clone(),
240 feature: face.feature.clone(),
241 mesh: pool.put(&Mesh::of(&face.mesh)?)?,
242 })
243 })
244 .collect::<GeopResult<_>>()?;
245 let instances = (view.instances.iter())
246 .map(|instance| {
247 let key = match placed.get(&Rc::as_ptr(&instance.view)) {
248 Some(key) => key.clone(),
249 None => {
250 let inner = written(&instance.view, pool, placed)?;
251 let key = pool.put(&inner)?;
252 placed.insert(Rc::as_ptr(&instance.view), key.clone());
253 key
254 }
255 };
256 Ok(Instance {
257 name: instance.name.clone(),
258 component: instance.component.clone(),
259 pose: instance.pose,
260 view: key,
261 state: instance.state.clone(),
262 fixed: instance.fixed,
263 })
264 })
265 .collect::<GeopResult<_>>()?;
266 Ok(Written {
267 model: view.model.clone(),
268 vertices: (view.vertices.iter())
269 .map(|v| Vertex {
270 name: v.name.clone(),
271 solid: v.solid.clone(),
272 faces: v.faces.clone(),
273 at: v.at,
274 })
275 .collect(),
276 edges: (view.edges.iter())
277 .map(|e| Edge {
278 name: e.name.clone(),
279 solid: e.solid.clone(),
280 faces: e.faces.clone(),
281 polyline: e.polyline.clone(),
282 within_a_surface: e.within_a_surface,
283 ends: e.ends.clone(),
284 })
285 .collect(),
286 faces,
287 datum_target: view.datum_target.clone(),
288 datums: (view.datums.iter())
289 .map(|d| Datum {
290 name: d.name.clone(),
291 kind: d.kind,
292 frame: d.frame.clone(),
293 components: d.components.clone(),
294 })
295 .collect(),
296 annotations: (view.annotations.iter())
297 .map(|a| Annotation {
298 name: a.name.clone(),
299 label: a.label.clone(),
300 polyline: a.polyline.clone(),
301 })
302 .collect(),
303 solids: view.solids.clone(),
304 instances,
305 center: view.extent.center,
306 size: view.extent.size,
307 color: view.color.clone(),
308 face_colors: view.face_colors.clone(),
309 })
310}
311
312fn view_of(
315 written: Written,
316 pool: &Pool,
317 placed: &mut HashMap<String, Rc<PartView>>,
318) -> GeopResult<PartView> {
319 let faces = (written.faces.into_iter())
320 .map(|face| {
321 let mesh: Mesh = pool.get(&face.mesh)?;
322 Ok(ViewFace {
323 name: face.name,
324 also: face.also,
325 solid: face.solid,
326 feature: face.feature,
327 mesh: Rc::new(mesh.mesh()?),
328 })
329 })
330 .collect::<GeopResult<_>>()?;
331 let mut instances = Vec::new();
332 for instance in written.instances {
333 let view = match placed.get(&instance.view) {
334 Some(view) => view.clone(),
335 None => {
336 let inner: Written = pool.get(&instance.view)?;
337 let view = Rc::new(view_of(inner, pool, placed)?);
338 placed.insert(instance.view.clone(), view.clone());
339 view
340 }
341 };
342 let origin = CoordinateSystem::world_at(Vector::zero());
343 instances.push(ViewInstance {
344 frame: instance.pose.motion().apply_frame(&origin)?,
345 name: instance.name,
346 component: instance.component,
347 pose: instance.pose,
348 view,
349 state: instance.state,
350 fixed: instance.fixed,
351 color: None,
352 });
353 }
354 Ok(PartView {
355 model: written.model,
356 vertices: (written.vertices.into_iter())
357 .map(|v| ViewVertex {
358 name: v.name,
359 solid: v.solid,
360 faces: v.faces,
361 at: v.at,
362 })
363 .collect(),
364 edges: (written.edges.into_iter())
365 .map(|e| ViewEdge {
366 name: e.name,
367 solid: e.solid,
368 faces: e.faces,
369 polyline: e.polyline,
370 within_a_surface: e.within_a_surface,
371 ends: e.ends,
372 })
373 .collect(),
374 faces,
375 sketches: Vec::new(),
376 datum_target: written.datum_target,
377 datums: (written.datums.into_iter())
378 .map(|d| ViewDatum {
379 name: d.name,
380 kind: d.kind,
381 frame: d.frame,
382 components: d.components,
383 })
384 .collect(),
385 annotations: (written.annotations.into_iter())
386 .map(|a| ViewAnnotation {
387 name: a.name,
388 label: a.label,
389 polyline: a.polyline,
390 })
391 .collect(),
392 solids: written.solids,
393 instances,
394 extent: Extent {
395 center: written.center,
396 size: written.size,
397 },
398 color: written.color,
399 face_colors: written.face_colors,
400 faces_tree: std::cell::RefCell::default(),
401 })
402}
403
404fn broken(what: &str) -> GeopError {
405 GeopError::new(format!("reading a kept view: {what} are not all there"))
406}