1use wasm_bindgen::prelude::*;
6
7#[wasm_bindgen]
10pub struct SymbolicPolyline {
11 express_id: u32,
12 ifc_type: String,
13 points: Vec<f32>,
15 is_closed: bool,
17 world_y: f32,
24 rep_identifier: String,
26}
27
28#[wasm_bindgen]
29impl SymbolicPolyline {
30 #[wasm_bindgen(getter, js_name = expressId)]
32 pub fn express_id(&self) -> u32 {
33 self.express_id
34 }
35
36 #[wasm_bindgen(getter, js_name = ifcType)]
38 pub fn ifc_type(&self) -> String {
39 self.ifc_type.clone()
40 }
41
42 #[wasm_bindgen(getter)]
44 pub fn points(&self) -> js_sys::Float32Array {
45 js_sys::Float32Array::from(&self.points[..])
46 }
47
48 #[wasm_bindgen(getter, js_name = pointCount)]
50 pub fn point_count(&self) -> usize {
51 self.points.len() / 2
52 }
53
54 #[wasm_bindgen(getter, js_name = isClosed)]
56 pub fn is_closed(&self) -> bool {
57 self.is_closed
58 }
59
60 #[wasm_bindgen(getter, js_name = repIdentifier)]
62 pub fn rep_identifier(&self) -> String {
63 self.rep_identifier.clone()
64 }
65
66 #[wasm_bindgen(getter, js_name = worldY)]
69 pub fn world_y(&self) -> f32 {
70 self.world_y
71 }
72}
73
74impl SymbolicPolyline {
75 #[allow(clippy::too_many_arguments)]
77 pub fn new(
78 express_id: u32,
79 ifc_type: String,
80 points: Vec<f32>,
81 is_closed: bool,
82 world_y: f32,
83 rep_identifier: String,
84 ) -> Self {
85 Self {
86 express_id,
87 ifc_type,
88 points,
89 is_closed,
90 world_y,
91 rep_identifier,
92 }
93 }
94}
95
96#[wasm_bindgen]
98pub struct SymbolicCircle {
99 express_id: u32,
100 ifc_type: String,
101 center_x: f32,
103 center_y: f32,
104 radius: f32,
106 world_y: f32,
108 start_angle: f32,
110 end_angle: f32,
112 rep_identifier: String,
114}
115
116#[wasm_bindgen]
117impl SymbolicCircle {
118 #[wasm_bindgen(getter, js_name = expressId)]
119 pub fn express_id(&self) -> u32 {
120 self.express_id
121 }
122
123 #[wasm_bindgen(getter, js_name = ifcType)]
124 pub fn ifc_type(&self) -> String {
125 self.ifc_type.clone()
126 }
127
128 #[wasm_bindgen(getter, js_name = centerX)]
129 pub fn center_x(&self) -> f32 {
130 self.center_x
131 }
132
133 #[wasm_bindgen(getter, js_name = centerY)]
134 pub fn center_y(&self) -> f32 {
135 self.center_y
136 }
137
138 #[wasm_bindgen(getter)]
139 pub fn radius(&self) -> f32 {
140 self.radius
141 }
142
143 #[wasm_bindgen(getter, js_name = startAngle)]
144 pub fn start_angle(&self) -> f32 {
145 self.start_angle
146 }
147
148 #[wasm_bindgen(getter, js_name = endAngle)]
149 pub fn end_angle(&self) -> f32 {
150 self.end_angle
151 }
152
153 #[wasm_bindgen(getter, js_name = repIdentifier)]
154 pub fn rep_identifier(&self) -> String {
155 self.rep_identifier.clone()
156 }
157
158 #[wasm_bindgen(getter, js_name = isFullCircle)]
160 pub fn is_full_circle(&self) -> bool {
161 (self.end_angle - self.start_angle - std::f32::consts::TAU).abs() < 0.001
162 }
163
164 #[wasm_bindgen(getter, js_name = worldY)]
166 pub fn world_y(&self) -> f32 {
167 self.world_y
168 }
169}
170
171impl SymbolicCircle {
172 #[allow(clippy::too_many_arguments)]
173 pub fn new(
174 express_id: u32,
175 ifc_type: String,
176 center_x: f32,
177 center_y: f32,
178 radius: f32,
179 world_y: f32,
180 start_angle: f32,
181 end_angle: f32,
182 rep_identifier: String,
183 ) -> Self {
184 Self {
185 express_id,
186 ifc_type,
187 center_x,
188 center_y,
189 radius,
190 world_y,
191 start_angle,
192 end_angle,
193 rep_identifier,
194 }
195 }
196
197 pub fn full_circle(
199 express_id: u32,
200 ifc_type: String,
201 center_x: f32,
202 center_y: f32,
203 radius: f32,
204 world_y: f32,
205 rep_identifier: String,
206 ) -> Self {
207 Self::new(
208 express_id,
209 ifc_type,
210 center_x,
211 center_y,
212 radius,
213 world_y,
214 0.0,
215 std::f32::consts::TAU,
216 rep_identifier,
217 )
218 }
219}
220
221#[wasm_bindgen]
231pub struct SymbolicText {
232 express_id: u32,
233 ifc_type: String,
234 x: f32,
236 y: f32,
237 dir_x: f32,
239 dir_y: f32,
240 height: f32,
243 content: String,
245 alignment: String,
248 world_y: f32,
251 color_r: f32,
257 color_g: f32,
258 color_b: f32,
259 color_a: f32,
260 target_px: f32,
265 rep_identifier: String,
267}
268
269#[wasm_bindgen]
270impl SymbolicText {
271 #[wasm_bindgen(getter, js_name = expressId)]
272 pub fn express_id(&self) -> u32 { self.express_id }
273 #[wasm_bindgen(getter, js_name = ifcType)]
274 pub fn ifc_type(&self) -> String { self.ifc_type.clone() }
275 #[wasm_bindgen(getter)]
276 pub fn x(&self) -> f32 { self.x }
277 #[wasm_bindgen(getter)]
278 pub fn y(&self) -> f32 { self.y }
279 #[wasm_bindgen(getter, js_name = dirX)]
280 pub fn dir_x(&self) -> f32 { self.dir_x }
281 #[wasm_bindgen(getter, js_name = dirY)]
282 pub fn dir_y(&self) -> f32 { self.dir_y }
283 #[wasm_bindgen(getter)]
284 pub fn height(&self) -> f32 { self.height }
285 #[wasm_bindgen(getter)]
286 pub fn content(&self) -> String { self.content.clone() }
287 #[wasm_bindgen(getter)]
288 pub fn alignment(&self) -> String { self.alignment.clone() }
289 #[wasm_bindgen(getter, js_name = worldY)]
290 pub fn world_y(&self) -> f32 { self.world_y }
291 #[wasm_bindgen(getter, js_name = colorR)]
292 pub fn color_r(&self) -> f32 { self.color_r }
293 #[wasm_bindgen(getter, js_name = colorG)]
294 pub fn color_g(&self) -> f32 { self.color_g }
295 #[wasm_bindgen(getter, js_name = colorB)]
296 pub fn color_b(&self) -> f32 { self.color_b }
297 #[wasm_bindgen(getter, js_name = colorA)]
298 pub fn color_a(&self) -> f32 { self.color_a }
299 #[wasm_bindgen(getter, js_name = targetPx)]
300 pub fn target_px(&self) -> f32 { self.target_px }
301 #[wasm_bindgen(getter, js_name = repIdentifier)]
302 pub fn rep_identifier(&self) -> String { self.rep_identifier.clone() }
303}
304
305impl SymbolicText {
306 #[allow(clippy::too_many_arguments)]
307 pub fn new(
308 express_id: u32,
309 ifc_type: String,
310 x: f32,
311 y: f32,
312 dir_x: f32,
313 dir_y: f32,
314 height: f32,
315 content: String,
316 alignment: String,
317 world_y: f32,
318 rep_identifier: String,
319 ) -> Self {
320 Self::new_styled(
321 express_id, ifc_type, x, y, dir_x, dir_y,
322 height, content, alignment, world_y,
323 [0.05, 0.05, 0.05, 1.0], 0.0, rep_identifier,
326 )
327 }
328
329 #[allow(clippy::too_many_arguments)]
333 pub fn new_styled(
334 express_id: u32,
335 ifc_type: String,
336 x: f32,
337 y: f32,
338 dir_x: f32,
339 dir_y: f32,
340 height: f32,
341 content: String,
342 alignment: String,
343 world_y: f32,
344 rgba: [f32; 4],
345 target_px: f32,
346 rep_identifier: String,
347 ) -> Self {
348 Self {
349 express_id,
350 ifc_type,
351 x,
352 y,
353 dir_x,
354 dir_y,
355 height,
356 content,
357 alignment,
358 world_y,
359 color_r: rgba[0],
360 color_g: rgba[1],
361 color_b: rgba[2],
362 color_a: rgba[3],
363 target_px,
364 rep_identifier,
365 }
366 }
367}
368
369#[wasm_bindgen]
383pub struct SymbolicFillArea {
384 express_id: u32,
385 geometry_item_id: Option<u32>,
386 ifc_type: String,
387 points: Vec<f32>,
390 holes_offsets: Vec<u32>,
393 fill_r: f32,
395 fill_g: f32,
396 fill_b: f32,
397 fill_a: f32,
398 has_hatching: bool,
400 hatch_spacing: f32,
402 hatch_angle: f32,
404 hatch_angle_secondary: f32,
406 hatch_line_width: f32,
408 world_y: f32,
411 rep_identifier: String,
412}
413
414#[wasm_bindgen]
415impl SymbolicFillArea {
416 #[wasm_bindgen(getter, js_name = geometryItemId)]
417 pub fn geometry_item_id(&self) -> Option<u32> { self.geometry_item_id }
418 #[wasm_bindgen(getter, js_name = expressId)]
419 pub fn express_id(&self) -> u32 { self.express_id }
420 #[wasm_bindgen(getter, js_name = ifcType)]
421 pub fn ifc_type(&self) -> String { self.ifc_type.clone() }
422 #[wasm_bindgen(getter)]
424 pub fn points(&self) -> js_sys::Float32Array {
425 js_sys::Float32Array::from(&self.points[..])
426 }
427 #[wasm_bindgen(getter, js_name = pointCount)]
428 pub fn point_count(&self) -> usize { self.points.len() / 2 }
429 #[wasm_bindgen(getter, js_name = holesOffsets)]
431 pub fn holes_offsets(&self) -> js_sys::Uint32Array {
432 js_sys::Uint32Array::from(&self.holes_offsets[..])
433 }
434 #[wasm_bindgen(getter, js_name = holeCount)]
435 pub fn hole_count(&self) -> usize { self.holes_offsets.len() }
436 #[wasm_bindgen(getter, js_name = fillR)]
437 pub fn fill_r(&self) -> f32 { self.fill_r }
438 #[wasm_bindgen(getter, js_name = fillG)]
439 pub fn fill_g(&self) -> f32 { self.fill_g }
440 #[wasm_bindgen(getter, js_name = fillB)]
441 pub fn fill_b(&self) -> f32 { self.fill_b }
442 #[wasm_bindgen(getter, js_name = fillA)]
443 pub fn fill_a(&self) -> f32 { self.fill_a }
444 #[wasm_bindgen(getter, js_name = hasHatching)]
445 pub fn has_hatching(&self) -> bool { self.has_hatching }
446 #[wasm_bindgen(getter, js_name = hatchSpacing)]
447 pub fn hatch_spacing(&self) -> f32 { self.hatch_spacing }
448 #[wasm_bindgen(getter, js_name = hatchAngle)]
449 pub fn hatch_angle(&self) -> f32 { self.hatch_angle }
450 #[wasm_bindgen(getter, js_name = hatchAngleSecondary)]
451 pub fn hatch_angle_secondary(&self) -> f32 { self.hatch_angle_secondary }
452 #[wasm_bindgen(getter, js_name = hatchLineWidth)]
453 pub fn hatch_line_width(&self) -> f32 { self.hatch_line_width }
454 #[wasm_bindgen(getter, js_name = worldY)]
455 pub fn world_y(&self) -> f32 { self.world_y }
456 #[wasm_bindgen(getter, js_name = repIdentifier)]
457 pub fn rep_identifier(&self) -> String { self.rep_identifier.clone() }
458}
459
460impl SymbolicFillArea {
461 pub(super) fn with_geometry_item_id(mut self, id: Option<u32>) -> Self {
462 self.geometry_item_id = id;
463 self
464 }
465
466 #[allow(clippy::too_many_arguments)]
467 pub fn new(
468 express_id: u32,
469 ifc_type: String,
470 points: Vec<f32>,
471 holes_offsets: Vec<u32>,
472 fill_rgba: [f32; 4],
473 world_y: f32,
474 rep_identifier: String,
475 ) -> Self {
476 Self {
477 express_id,
478 geometry_item_id: None,
479 ifc_type,
480 points,
481 holes_offsets,
482 fill_r: fill_rgba[0],
483 fill_g: fill_rgba[1],
484 fill_b: fill_rgba[2],
485 fill_a: fill_rgba[3],
486 has_hatching: false,
487 hatch_spacing: 0.0,
488 hatch_angle: 0.0,
489 hatch_angle_secondary: f32::NAN,
490 hatch_line_width: 0.0,
491 world_y,
492 rep_identifier,
493 }
494 }
495
496 pub fn with_hatching(
498 mut self,
499 spacing: f32,
500 angle: f32,
501 angle_secondary: Option<f32>,
502 line_width: f32,
503 ) -> Self {
504 self.has_hatching = true;
505 self.hatch_spacing = spacing;
506 self.hatch_angle = angle;
507 self.hatch_angle_secondary = angle_secondary.unwrap_or(f32::NAN);
508 self.hatch_line_width = line_width;
509 self
510 }
511}
512
513#[wasm_bindgen]
515pub struct SymbolicRepresentationCollection {
516 polylines: Vec<SymbolicPolyline>,
517 circles: Vec<SymbolicCircle>,
518 texts: Vec<SymbolicText>,
519 fills: Vec<SymbolicFillArea>,
520 pub(super) truncated: Option<ifc_lite_processing::SymbolicTruncation>,
528}
529
530#[wasm_bindgen]
531impl SymbolicRepresentationCollection {
532 #[wasm_bindgen(js_name = getExpressIds)]
534 pub fn get_express_ids(&self) -> Vec<u32> {
535 let mut ids: Vec<u32> = self
536 .polylines
537 .iter()
538 .map(|p| p.express_id)
539 .chain(self.circles.iter().map(|c| c.express_id))
540 .chain(self.texts.iter().map(|t| t.express_id))
541 .chain(self.fills.iter().map(|f| f.express_id))
542 .collect();
543 ids.sort_unstable();
544 ids.dedup();
545 ids
546 }
547
548 #[wasm_bindgen(getter, js_name = polylineCount)]
550 pub fn polyline_count(&self) -> usize {
551 self.polylines.len()
552 }
553
554 #[wasm_bindgen(getter, js_name = circleCount)]
556 pub fn circle_count(&self) -> usize {
557 self.circles.len()
558 }
559
560 #[wasm_bindgen(getter, js_name = textCount)]
562 pub fn text_count(&self) -> usize { self.texts.len() }
563
564 #[wasm_bindgen(getter, js_name = fillCount)]
566 pub fn fill_count(&self) -> usize { self.fills.len() }
567
568 #[wasm_bindgen(getter, js_name = totalCount)]
570 pub fn total_count(&self) -> usize {
571 self.polylines.len() + self.circles.len() + self.texts.len() + self.fills.len()
572 }
573
574 #[wasm_bindgen(getter, js_name = isEmpty)]
577 pub fn is_empty(&self) -> bool {
578 self.polylines.is_empty()
579 && self.circles.is_empty()
580 && self.texts.is_empty()
581 && self.fills.is_empty()
582 && self.truncated.is_none()
583 }
584
585 #[wasm_bindgen(js_name = getPolyline)]
587 pub fn get_polyline(&self, index: usize) -> Option<SymbolicPolyline> {
588 self.polylines.get(index).map(|p| SymbolicPolyline {
589 express_id: p.express_id,
590 ifc_type: p.ifc_type.clone(),
591 points: p.points.clone(),
592 is_closed: p.is_closed,
593 world_y: p.world_y,
594 rep_identifier: p.rep_identifier.clone(),
595 })
596 }
597
598 #[wasm_bindgen(js_name = getCircle)]
600 pub fn get_circle(&self, index: usize) -> Option<SymbolicCircle> {
601 self.circles.get(index).map(|c| SymbolicCircle {
602 express_id: c.express_id,
603 ifc_type: c.ifc_type.clone(),
604 center_x: c.center_x,
605 center_y: c.center_y,
606 radius: c.radius,
607 world_y: c.world_y,
608 start_angle: c.start_angle,
609 end_angle: c.end_angle,
610 rep_identifier: c.rep_identifier.clone(),
611 })
612 }
613
614 #[wasm_bindgen(js_name = getText)]
616 pub fn get_text(&self, index: usize) -> Option<SymbolicText> {
617 self.texts.get(index).map(|t| SymbolicText {
618 express_id: t.express_id,
619 ifc_type: t.ifc_type.clone(),
620 x: t.x,
621 y: t.y,
622 dir_x: t.dir_x,
623 dir_y: t.dir_y,
624 height: t.height,
625 content: t.content.clone(),
626 alignment: t.alignment.clone(),
627 world_y: t.world_y,
628 color_r: t.color_r,
629 color_g: t.color_g,
630 color_b: t.color_b,
631 color_a: t.color_a,
632 target_px: t.target_px,
633 rep_identifier: t.rep_identifier.clone(),
634 })
635 }
636
637 #[wasm_bindgen(js_name = getFill)]
639 pub fn get_fill(&self, index: usize) -> Option<SymbolicFillArea> {
640 self.fills.get(index).map(|f| SymbolicFillArea {
641 express_id: f.express_id,
642 geometry_item_id: f.geometry_item_id,
643 ifc_type: f.ifc_type.clone(),
644 points: f.points.clone(),
645 holes_offsets: f.holes_offsets.clone(),
646 fill_r: f.fill_r,
647 fill_g: f.fill_g,
648 fill_b: f.fill_b,
649 fill_a: f.fill_a,
650 has_hatching: f.has_hatching,
651 hatch_spacing: f.hatch_spacing,
652 hatch_angle: f.hatch_angle,
653 hatch_angle_secondary: f.hatch_angle_secondary,
654 hatch_line_width: f.hatch_line_width,
655 world_y: f.world_y,
656 rep_identifier: f.rep_identifier.clone(),
657 })
658 }
659
660}
661
662impl SymbolicRepresentationCollection {
663 pub fn new() -> Self {
664 Self {
665 polylines: Vec::new(),
666 circles: Vec::new(),
667 texts: Vec::new(),
668 fills: Vec::new(),
669 truncated: None,
670 }
671 }
672
673 pub fn with_capacity(polyline_capacity: usize, circle_capacity: usize) -> Self {
674 Self {
675 polylines: Vec::with_capacity(polyline_capacity),
676 circles: Vec::with_capacity(circle_capacity),
677 texts: Vec::new(),
678 fills: Vec::new(),
679 truncated: None,
680 }
681 }
682
683 pub fn add_polyline(&mut self, polyline: SymbolicPolyline) {
684 self.polylines.push(polyline);
685 }
686
687 pub fn add_circle(&mut self, circle: SymbolicCircle) {
688 self.circles.push(circle);
689 }
690
691 pub fn add_text(&mut self, text: SymbolicText) {
692 self.texts.push(text);
693 }
694
695 pub fn add_fill(&mut self, fill: SymbolicFillArea) {
696 self.fills.push(fill);
697 }
698}
699
700impl Default for SymbolicRepresentationCollection {
701 fn default() -> Self {
702 Self::new()
703 }
704}