1use crate::entities::{Entity, EntityCommon};
7use crate::types::{BoundingBox3D, Color, Handle, LineWeight, Transparency, Vector3};
8
9use bitflags::bitflags;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[repr(i16)]
19pub enum LeaderContentType {
20 None = 0,
22 Block = 1,
24 #[default]
26 MText = 2,
27 Tolerance = 3,
29}
30
31impl From<i16> for LeaderContentType {
32 fn from(value: i16) -> Self {
33 match value {
34 0 => Self::None,
35 1 => Self::Block,
36 2 => Self::MText,
37 3 => Self::Tolerance,
38 _ => Self::None,
39 }
40 }
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46#[repr(i16)]
47pub enum MultiLeaderPathType {
48 Invisible = 0,
50 #[default]
52 StraightLineSegments = 1,
53 Spline = 2,
55}
56
57impl From<i16> for MultiLeaderPathType {
58 fn from(value: i16) -> Self {
59 match value {
60 0 => Self::Invisible,
61 1 => Self::StraightLineSegments,
62 2 => Self::Spline,
63 _ => Self::StraightLineSegments,
64 }
65 }
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71#[repr(i16)]
72pub enum TextAttachmentType {
73 TopOfTopLine = 0,
75 MiddleOfTopLine = 1,
77 #[default]
79 MiddleOfText = 2,
80 MiddleOfBottomLine = 3,
82 BottomOfBottomLine = 4,
84 BottomLine = 5,
86 BottomOfTopLineUnderlineBottomLine = 6,
88 BottomOfTopLineUnderlineTopLine = 7,
90 BottomOfTopLineUnderlineAll = 8,
92 CenterOfText = 9,
94 CenterOfTextOverline = 10,
96}
97
98impl From<i16> for TextAttachmentType {
99 fn from(value: i16) -> Self {
100 match value {
101 0 => Self::TopOfTopLine,
102 1 => Self::MiddleOfTopLine,
103 2 => Self::MiddleOfText,
104 3 => Self::MiddleOfBottomLine,
105 4 => Self::BottomOfBottomLine,
106 5 => Self::BottomLine,
107 6 => Self::BottomOfTopLineUnderlineBottomLine,
108 7 => Self::BottomOfTopLineUnderlineTopLine,
109 8 => Self::BottomOfTopLineUnderlineAll,
110 9 => Self::CenterOfText,
111 10 => Self::CenterOfTextOverline,
112 _ => Self::MiddleOfText,
113 }
114 }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
119#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
120#[repr(i16)]
121pub enum TextAngleType {
122 ParallelToLastLeaderLine = 0,
124 #[default]
126 Horizontal = 1,
127 Optimized = 2,
129}
130
131impl From<i16> for TextAngleType {
132 fn from(value: i16) -> Self {
133 match value {
134 0 => Self::ParallelToLastLeaderLine,
135 1 => Self::Horizontal,
136 2 => Self::Optimized,
137 _ => Self::Horizontal,
138 }
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
144#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
145#[repr(i16)]
146pub enum BlockContentConnectionType {
147 #[default]
149 BlockExtents = 0,
150 BasePoint = 1,
152}
153
154impl From<i16> for BlockContentConnectionType {
155 fn from(value: i16) -> Self {
156 match value {
157 0 => Self::BlockExtents,
158 1 => Self::BasePoint,
159 _ => Self::BlockExtents,
160 }
161 }
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
166#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
167#[repr(i16)]
168pub enum TextAttachmentDirectionType {
169 #[default]
171 Horizontal = 0,
172 Vertical = 1,
174}
175
176impl From<i16> for TextAttachmentDirectionType {
177 fn from(value: i16) -> Self {
178 match value {
179 0 => Self::Horizontal,
180 1 => Self::Vertical,
181 _ => Self::Horizontal,
182 }
183 }
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
189#[repr(i16)]
190pub enum TextAttachmentPointType {
191 Left = 1,
193 #[default]
195 Center = 2,
196 Right = 3,
198}
199
200impl From<i16> for TextAttachmentPointType {
201 fn from(value: i16) -> Self {
202 match value {
203 1 => Self::Left,
204 2 => Self::Center,
205 3 => Self::Right,
206 _ => Self::Center,
207 }
208 }
209}
210
211#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
213#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
214#[repr(i16)]
215pub enum TextAlignmentType {
216 #[default]
218 Left = 0,
219 Center = 1,
221 Right = 2,
223}
224
225impl From<i16> for TextAlignmentType {
226 fn from(value: i16) -> Self {
227 match value {
228 0 => Self::Left,
229 1 => Self::Center,
230 2 => Self::Right,
231 _ => Self::Left,
232 }
233 }
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
238#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
239#[repr(i16)]
240pub enum FlowDirectionType {
241 #[default]
243 Horizontal = 1,
244 Vertical = 3,
246 ByStyle = 5,
248}
249
250impl From<i16> for FlowDirectionType {
251 fn from(value: i16) -> Self {
252 match value {
253 1 => Self::Horizontal,
254 3 => Self::Vertical,
255 5 => Self::ByStyle,
256 _ => Self::Horizontal,
257 }
258 }
259}
260
261#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
263#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
264#[repr(i16)]
265pub enum LineSpacingStyle {
266 #[default]
268 AtLeast = 1,
269 Exactly = 2,
271}
272
273impl From<i16> for LineSpacingStyle {
274 fn from(value: i16) -> Self {
275 match value {
276 1 => Self::AtLeast,
277 2 => Self::Exactly,
278 _ => Self::AtLeast,
279 }
280 }
281}
282
283bitflags! {
288 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
290 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
291 pub struct MultiLeaderPropertyOverrideFlags: u32 {
292 const NONE = 0;
294 const PATH_TYPE = 0x1;
296 const LINE_COLOR = 0x2;
298 const LEADER_LINE_TYPE = 0x4;
300 const LEADER_LINE_WEIGHT = 0x8;
302 const ENABLE_LANDING = 0x10;
304 const LANDING_GAP = 0x20;
306 const ENABLE_DOGLEG = 0x40;
308 const LANDING_DISTANCE = 0x80;
310 const ARROWHEAD = 0x100;
312 const ARROWHEAD_SIZE = 0x200;
314 const CONTENT_TYPE = 0x400;
316 const TEXT_STYLE = 0x800;
318 const TEXT_LEFT_ATTACHMENT = 0x1000;
320 const TEXT_ANGLE = 0x2000;
322 const TEXT_ALIGNMENT = 0x4000;
324 const TEXT_COLOR = 0x8000;
326 const TEXT_HEIGHT = 0x10000;
328 const TEXT_FRAME = 0x20000;
330 const ENABLE_USE_DEFAULT_MTEXT = 0x40000;
332 const BLOCK_CONTENT = 0x80000;
334 const BLOCK_CONTENT_COLOR = 0x100000;
336 const BLOCK_CONTENT_SCALE = 0x200000;
338 const BLOCK_CONTENT_ROTATION = 0x400000;
340 const BLOCK_CONTENT_CONNECTION = 0x800000;
342 const SCALE_FACTOR = 0x1000000;
344 const TEXT_RIGHT_ATTACHMENT = 0x2000000;
346 const TEXT_SWITCH_ALIGNMENT_TYPE = 0x4000000;
348 const TEXT_ATTACHMENT_DIRECTION = 0x8000000;
350 const TEXT_TOP_ATTACHMENT = 0x10000000;
352 const TEXT_BOTTOM_ATTACHMENT = 0x20000000;
354 }
355}
356
357bitflags! {
358 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
360 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
361 pub struct LeaderLinePropertyOverrideFlags: u32 {
362 const NONE = 0;
364 const PATH_TYPE = 1;
366 const LINE_COLOR = 2;
368 const LINE_TYPE = 4;
370 const LINE_WEIGHT = 8;
372 const ARROWHEAD_SIZE = 16;
374 const ARROWHEAD = 32;
376 }
377}
378
379#[derive(Debug, Clone, Copy, PartialEq)]
385#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
386pub struct StartEndPointPair {
387 pub start_point: Vector3,
389 pub end_point: Vector3,
391}
392
393impl StartEndPointPair {
394 pub fn new(start_point: Vector3, end_point: Vector3) -> Self {
396 Self {
397 start_point,
398 end_point,
399 }
400 }
401}
402
403impl Default for StartEndPointPair {
404 fn default() -> Self {
405 Self {
406 start_point: Vector3::ZERO,
407 end_point: Vector3::ZERO,
408 }
409 }
410}
411
412#[derive(Debug, Clone, PartialEq)]
414#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
415pub struct LeaderLine {
416 pub index: i32,
418 pub segment_index: i32,
420 pub points: Vec<Vector3>,
422 pub break_points: Vec<StartEndPointPair>,
424 pub break_info_count: i32,
426 pub path_type: MultiLeaderPathType,
428 pub line_color: Color,
430 pub line_type_handle: Option<Handle>,
432 pub line_weight: LineWeight,
434 pub arrowhead_handle: Option<Handle>,
436 pub arrowhead_size: f64,
438 pub override_flags: LeaderLinePropertyOverrideFlags,
440}
441
442impl LeaderLine {
443 pub fn new(index: i32) -> Self {
445 Self {
446 index,
447 segment_index: 0,
448 points: Vec::new(),
449 break_points: Vec::new(),
450 break_info_count: 0,
451 path_type: MultiLeaderPathType::StraightLineSegments,
452 line_color: Color::ByBlock,
453 line_type_handle: None,
454 line_weight: LineWeight::ByLayer,
455 arrowhead_handle: None,
456 arrowhead_size: 0.18,
457 override_flags: LeaderLinePropertyOverrideFlags::NONE,
458 }
459 }
460
461 pub fn from_points(index: i32, points: Vec<Vector3>) -> Self {
463 let mut line = Self::new(index);
464 line.points = points;
465 line
466 }
467
468 pub fn add_point(&mut self, point: Vector3) {
470 self.points.push(point);
471 }
472
473 pub fn point_count(&self) -> usize {
475 self.points.len()
476 }
477
478 pub fn start_point(&self) -> Option<Vector3> {
480 self.points.first().copied()
481 }
482
483 pub fn end_point(&self) -> Option<Vector3> {
485 self.points.last().copied()
486 }
487
488 pub fn length(&self) -> f64 {
490 if self.points.len() < 2 {
491 return 0.0;
492 }
493 self.points
494 .windows(2)
495 .map(|w| (w[1] - w[0]).length())
496 .sum()
497 }
498}
499
500impl Default for LeaderLine {
501 fn default() -> Self {
502 Self::new(0)
503 }
504}
505
506#[derive(Debug, Clone, PartialEq)]
508#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
509pub struct LeaderRoot {
510 pub leader_index: i32,
512 pub content_valid: bool,
514 pub unknown: bool,
516 pub connection_point: Vector3,
518 pub direction: Vector3,
520 pub break_points: Vec<StartEndPointPair>,
522 pub lines: Vec<LeaderLine>,
524 pub landing_distance: f64,
526 pub text_attachment_direction: TextAttachmentDirectionType,
528}
529
530impl LeaderRoot {
531 pub fn new(index: i32) -> Self {
533 Self {
534 leader_index: index,
535 content_valid: true,
536 unknown: true,
537 connection_point: Vector3::ZERO,
538 direction: Vector3::new(1.0, 0.0, 0.0),
539 break_points: Vec::new(),
540 lines: Vec::new(),
541 landing_distance: 0.36,
542 text_attachment_direction: TextAttachmentDirectionType::Horizontal,
543 }
544 }
545
546 pub fn add_line(&mut self, line: LeaderLine) {
548 self.lines.push(line);
549 }
550
551 pub fn create_line(&mut self, points: Vec<Vector3>) -> &mut LeaderLine {
553 let index = self.lines.len() as i32;
554 let line = LeaderLine::from_points(index, points);
555 self.lines.push(line);
556 self.lines.last_mut().unwrap()
557 }
558
559 pub fn line_count(&self) -> usize {
561 self.lines.len()
562 }
563}
564
565impl Default for LeaderRoot {
566 fn default() -> Self {
567 Self::new(0)
568 }
569}
570
571#[derive(Debug, Clone, PartialEq)]
573#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
574pub struct BlockAttribute {
575 pub attribute_definition_handle: Option<Handle>,
577 pub index: i16,
579 pub width: f64,
581 pub text: String,
583}
584
585impl BlockAttribute {
586 pub fn new(text: &str) -> Self {
588 Self {
589 attribute_definition_handle: None,
590 index: 0,
591 width: 0.0,
592 text: text.to_string(),
593 }
594 }
595}
596
597impl Default for BlockAttribute {
598 fn default() -> Self {
599 Self::new("")
600 }
601}
602
603#[derive(Debug, Clone, PartialEq)]
609#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
610pub struct MultiLeaderAnnotContext {
611 pub leader_roots: Vec<LeaderRoot>,
613
614 pub scale_factor: f64,
617 pub content_base_point: Vector3,
619
620 pub has_text_contents: bool,
623 pub text_string: String,
625 pub text_normal: Vector3,
627 pub text_location: Vector3,
629 pub text_direction: Vector3,
631 pub text_rotation: f64,
633 pub text_height: f64,
635 pub text_width: f64,
637 pub text_boundary_height: f64,
639 pub line_spacing_factor: f64,
641 pub line_spacing_style: LineSpacingStyle,
643 pub text_color: Color,
645 pub text_attachment_point: TextAttachmentPointType,
647 pub text_flow_direction: FlowDirectionType,
649 pub text_alignment: TextAlignmentType,
651 pub text_left_attachment: TextAttachmentType,
653 pub text_right_attachment: TextAttachmentType,
655 pub text_top_attachment: TextAttachmentType,
657 pub text_bottom_attachment: TextAttachmentType,
659 pub text_height_automatic: bool,
661 pub word_break: bool,
663 pub text_style_handle: Option<Handle>,
665
666 pub has_block_contents: bool,
669 pub block_content_handle: Option<Handle>,
671 pub block_content_normal: Vector3,
673 pub block_content_location: Vector3,
675 pub block_content_scale: Vector3,
677 pub block_rotation: f64,
679 pub block_content_color: Color,
681 pub block_connection_type: BlockContentConnectionType,
683
684 pub column_type: i16,
687 pub column_width: f64,
689 pub column_gutter: f64,
691 pub column_flow_reversed: bool,
693 pub column_sizes: Vec<f64>,
695
696 pub background_fill_enabled: bool,
699 pub background_mask_fill_on: bool,
701 pub background_fill_color: Color,
703 pub background_scale_factor: f64,
705 pub background_transparency: i32,
707
708 pub base_point: Vector3,
711 pub base_direction: Vector3,
713 pub base_vertical: Vector3,
715 pub normal_reversed: bool,
717
718 pub arrowhead_size: f64,
721 pub landing_gap: f64,
723
724 pub transform_matrix: [f64; 16],
727
728 pub scale_handle: Option<Handle>,
730}
731
732impl MultiLeaderAnnotContext {
733 pub fn new() -> Self {
735 let mut transform_matrix = [0.0; 16];
737 transform_matrix[0] = 1.0;
738 transform_matrix[5] = 1.0;
739 transform_matrix[10] = 1.0;
740 transform_matrix[15] = 1.0;
741
742 Self {
743 leader_roots: Vec::new(),
744 scale_factor: 1.0,
745 content_base_point: Vector3::ZERO,
746 has_text_contents: false,
747 text_string: String::new(),
748 text_normal: Vector3::new(0.0, 0.0, 1.0),
749 text_location: Vector3::ZERO,
750 text_direction: Vector3::new(1.0, 0.0, 0.0),
751 text_rotation: 0.0,
752 text_height: 0.18,
753 text_width: 0.0,
754 text_boundary_height: 0.0,
755 line_spacing_factor: 1.0,
756 line_spacing_style: LineSpacingStyle::AtLeast,
757 text_color: Color::ByBlock,
758 text_attachment_point: TextAttachmentPointType::Center,
759 text_flow_direction: FlowDirectionType::Horizontal,
760 text_alignment: TextAlignmentType::Left,
761 text_left_attachment: TextAttachmentType::MiddleOfText,
762 text_right_attachment: TextAttachmentType::MiddleOfText,
763 text_top_attachment: TextAttachmentType::CenterOfText,
764 text_bottom_attachment: TextAttachmentType::CenterOfText,
765 text_height_automatic: false,
766 word_break: true,
767 text_style_handle: None,
768 has_block_contents: false,
769 block_content_handle: None,
770 block_content_normal: Vector3::new(0.0, 0.0, 1.0),
771 block_content_location: Vector3::ZERO,
772 block_content_scale: Vector3::new(1.0, 1.0, 1.0),
773 block_rotation: 0.0,
774 block_content_color: Color::ByBlock,
775 block_connection_type: BlockContentConnectionType::BlockExtents,
776 column_type: 0,
777 column_width: 0.0,
778 column_gutter: 0.0,
779 column_flow_reversed: false,
780 column_sizes: Vec::new(),
781 background_fill_enabled: false,
782 background_mask_fill_on: false,
783 background_fill_color: Color::ByBlock,
784 background_scale_factor: 1.5,
785 background_transparency: 0,
786 base_point: Vector3::ZERO,
787 base_direction: Vector3::new(1.0, 0.0, 0.0),
788 base_vertical: Vector3::new(0.0, 1.0, 0.0),
789 normal_reversed: false,
790 arrowhead_size: 0.18,
791 landing_gap: 0.09,
792 transform_matrix,
793 scale_handle: None,
794 }
795 }
796
797 pub fn add_leader_root(&mut self) -> &mut LeaderRoot {
799 let index = self.leader_roots.len() as i32;
800 self.leader_roots.push(LeaderRoot::new(index));
801 self.leader_roots.last_mut().unwrap()
802 }
803
804 pub fn leader_root_count(&self) -> usize {
806 self.leader_roots.len()
807 }
808
809 pub fn set_text_content(&mut self, text: &str, location: Vector3) {
811 self.has_text_contents = true;
812 self.text_string = text.to_string();
813 self.text_location = location;
814 self.content_base_point = location;
815 }
816
817 pub fn set_block_content(&mut self, block_handle: Handle, location: Vector3) {
819 self.has_block_contents = true;
820 self.block_content_handle = Some(block_handle);
821 self.block_content_location = location;
822 self.content_base_point = location;
823 }
824}
825
826impl Default for MultiLeaderAnnotContext {
827 fn default() -> Self {
828 Self::new()
829 }
830}
831
832#[derive(Debug, Clone, PartialEq)]
859#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
860pub struct MultiLeader {
861 pub common: EntityCommon,
863
864 pub style_handle: Option<Handle>,
867
868 pub content_type: LeaderContentType,
871 pub context: MultiLeaderAnnotContext,
873 pub block_attributes: Vec<BlockAttribute>,
875
876 pub path_type: MultiLeaderPathType,
879 pub line_color: Color,
881 pub line_type_handle: Option<Handle>,
883 pub line_weight: LineWeight,
885 pub enable_landing: bool,
887 pub enable_dogleg: bool,
889 pub dogleg_length: f64,
891 pub arrowhead_handle: Option<Handle>,
893 pub arrowhead_size: f64,
895
896 pub text_style_handle: Option<Handle>,
899 pub text_color: Color,
901 pub text_frame: bool,
903 pub text_height: f64,
905 pub text_left_attachment: TextAttachmentType,
907 pub text_right_attachment: TextAttachmentType,
909 pub text_top_attachment: TextAttachmentType,
911 pub text_bottom_attachment: TextAttachmentType,
913 pub text_attachment_direction: TextAttachmentDirectionType,
915 pub text_attachment_point: TextAttachmentPointType,
917 pub text_alignment: TextAlignmentType,
919 pub text_angle_type: TextAngleType,
921 pub text_direction_negative: bool,
923 pub text_align_in_ipe: i16,
925
926 pub block_content_handle: Option<Handle>,
929 pub block_content_color: Color,
931 pub block_connection_type: BlockContentConnectionType,
933 pub block_rotation: f64,
935 pub block_scale: Vector3,
937
938 pub scale_factor: f64,
941 pub property_override_flags: MultiLeaderPropertyOverrideFlags,
943 pub enable_annotation_scale: bool,
945 pub extend_leader_to_text: bool,
947}
948
949impl MultiLeader {
950 pub fn new() -> Self {
952 Self {
953 common: EntityCommon::default(),
954 style_handle: None,
955 content_type: LeaderContentType::MText,
956 context: MultiLeaderAnnotContext::new(),
957 block_attributes: Vec::new(),
958 path_type: MultiLeaderPathType::StraightLineSegments,
959 line_color: Color::ByBlock,
960 line_type_handle: None,
961 line_weight: LineWeight::ByLayer,
962 enable_landing: true,
963 enable_dogleg: true,
964 dogleg_length: 0.36,
965 arrowhead_handle: None,
966 arrowhead_size: 0.18,
967 text_style_handle: None,
968 text_color: Color::ByBlock,
969 text_frame: false,
970 text_height: 0.18,
971 text_left_attachment: TextAttachmentType::MiddleOfText,
972 text_right_attachment: TextAttachmentType::MiddleOfText,
973 text_top_attachment: TextAttachmentType::CenterOfText,
974 text_bottom_attachment: TextAttachmentType::CenterOfText,
975 text_attachment_direction: TextAttachmentDirectionType::Horizontal,
976 text_attachment_point: TextAttachmentPointType::Center,
977 text_alignment: TextAlignmentType::Left,
978 text_angle_type: TextAngleType::Horizontal,
979 text_direction_negative: false,
980 text_align_in_ipe: 0,
981 block_content_handle: None,
982 block_content_color: Color::ByBlock,
983 block_connection_type: BlockContentConnectionType::BlockExtents,
984 block_rotation: 0.0,
985 block_scale: Vector3::new(1.0, 1.0, 1.0),
986 scale_factor: 1.0,
987 property_override_flags: MultiLeaderPropertyOverrideFlags::NONE,
988 enable_annotation_scale: true,
989 extend_leader_to_text: false,
990 }
991 }
992
993 pub fn with_text(text: &str, text_location: Vector3, leader_points: Vec<Vector3>) -> Self {
995 let mut mleader = Self::new();
996 mleader.set_text_content(text, text_location);
997
998 let root = mleader.add_leader_root();
1000 root.connection_point = text_location;
1001 if !leader_points.is_empty() {
1002 root.create_line(leader_points);
1003 }
1004
1005 mleader
1006 }
1007
1008 pub fn set_text_content(&mut self, text: &str, location: Vector3) {
1010 self.content_type = LeaderContentType::MText;
1011 self.context.set_text_content(text, location);
1012 }
1013
1014 pub fn set_block_content(&mut self, block_handle: Handle, location: Vector3) {
1016 self.content_type = LeaderContentType::Block;
1017 self.block_content_handle = Some(block_handle);
1018 self.context.set_block_content(block_handle, location);
1019 }
1020
1021 pub fn add_leader_root(&mut self) -> &mut LeaderRoot {
1023 self.context.add_leader_root()
1024 }
1025
1026 pub fn leader_root_count(&self) -> usize {
1028 self.context.leader_root_count()
1029 }
1030
1031 pub fn total_leader_line_count(&self) -> usize {
1033 self.context
1034 .leader_roots
1035 .iter()
1036 .map(|r| r.line_count())
1037 .sum()
1038 }
1039
1040 pub fn text(&self) -> Option<&str> {
1042 if self.content_type == LeaderContentType::MText && self.context.has_text_contents {
1043 Some(&self.context.text_string)
1044 } else {
1045 None
1046 }
1047 }
1048
1049 pub fn set_text(&mut self, text: &str) {
1051 if self.content_type == LeaderContentType::MText {
1052 self.context.text_string = text.to_string();
1053 self.context.has_text_contents = true;
1054 }
1055 }
1056
1057 pub fn translate(&mut self, offset: Vector3) {
1059 self.context.content_base_point = self.context.content_base_point + offset;
1061 self.context.text_location = self.context.text_location + offset;
1062 self.context.block_content_location = self.context.block_content_location + offset;
1063 self.context.base_point = self.context.base_point + offset;
1064
1065 for root in &mut self.context.leader_roots {
1067 root.connection_point = root.connection_point + offset;
1068 for bp in &mut root.break_points {
1069 bp.start_point = bp.start_point + offset;
1070 bp.end_point = bp.end_point + offset;
1071 }
1072 for line in &mut root.lines {
1073 for point in &mut line.points {
1074 *point = *point + offset;
1075 }
1076 for bp in &mut line.break_points {
1077 bp.start_point = bp.start_point + offset;
1078 bp.end_point = bp.end_point + offset;
1079 }
1080 }
1081 }
1082 }
1083
1084 pub fn bounding_box(&self) -> Option<(Vector3, Vector3)> {
1086 let mut points: Vec<Vector3> = Vec::new();
1087
1088 points.push(self.context.content_base_point);
1090
1091 for root in &self.context.leader_roots {
1093 points.push(root.connection_point);
1094 for line in &root.lines {
1095 points.extend(&line.points);
1096 }
1097 }
1098
1099 if points.is_empty() {
1100 return None;
1101 }
1102
1103 let mut min = points[0];
1104 let mut max = points[0];
1105
1106 for p in &points[1..] {
1107 min.x = min.x.min(p.x);
1108 min.y = min.y.min(p.y);
1109 min.z = min.z.min(p.z);
1110 max.x = max.x.max(p.x);
1111 max.y = max.y.max(p.y);
1112 max.z = max.z.max(p.z);
1113 }
1114
1115 Some((min, max))
1116 }
1117}
1118
1119impl Default for MultiLeader {
1120 fn default() -> Self {
1121 Self::new()
1122 }
1123}
1124
1125impl Entity for MultiLeader {
1126 fn handle(&self) -> Handle {
1127 self.common.handle
1128 }
1129
1130 fn set_handle(&mut self, handle: Handle) {
1131 self.common.handle = handle;
1132 }
1133
1134 fn layer(&self) -> &str {
1135 &self.common.layer
1136 }
1137
1138 fn set_layer(&mut self, layer: String) {
1139 self.common.layer = layer;
1140 }
1141
1142 fn color(&self) -> Color {
1143 self.common.color
1144 }
1145
1146 fn set_color(&mut self, color: Color) {
1147 self.common.color = color;
1148 }
1149
1150 fn line_weight(&self) -> LineWeight {
1151 self.common.line_weight
1152 }
1153
1154 fn set_line_weight(&mut self, line_weight: LineWeight) {
1155 self.common.line_weight = line_weight;
1156 }
1157
1158 fn transparency(&self) -> Transparency {
1159 self.common.transparency
1160 }
1161
1162 fn set_transparency(&mut self, transparency: Transparency) {
1163 self.common.transparency = transparency;
1164 }
1165
1166 fn is_invisible(&self) -> bool {
1167 self.common.invisible
1168 }
1169
1170 fn set_invisible(&mut self, invisible: bool) {
1171 self.common.invisible = invisible;
1172 }
1173
1174 fn bounding_box(&self) -> BoundingBox3D {
1175 let mut min = Vector3::new(f64::MAX, f64::MAX, f64::MAX);
1177 let mut max = Vector3::new(f64::MIN, f64::MIN, f64::MIN);
1178
1179 let loc = &self.context.content_base_point;
1181 min.x = min.x.min(loc.x);
1182 min.y = min.y.min(loc.y);
1183 min.z = min.z.min(loc.z);
1184 max.x = max.x.max(loc.x);
1185 max.y = max.y.max(loc.y);
1186 max.z = max.z.max(loc.z);
1187
1188 for root in &self.context.leader_roots {
1190 for line in &root.lines {
1191 for pt in &line.points {
1192 min.x = min.x.min(pt.x);
1193 min.y = min.y.min(pt.y);
1194 min.z = min.z.min(pt.z);
1195 max.x = max.x.max(pt.x);
1196 max.y = max.y.max(pt.y);
1197 max.z = max.z.max(pt.z);
1198 }
1199 }
1200 }
1201
1202 BoundingBox3D::new(min, max)
1203 }
1204
1205 fn translate(&mut self, offset: Vector3) {
1206 super::translate::translate_multileader(self, offset);
1207 }
1208
1209 fn entity_type(&self) -> &'static str {
1210 "MULTILEADER"
1211 }
1212
1213 fn apply_transform(&mut self, transform: &crate::types::Transform) {
1214 super::transform::transform_multileader(self, transform);
1215 }
1216}
1217
1218#[derive(Debug, Clone)]
1224#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1225pub struct MultiLeaderBuilder {
1226 multileader: MultiLeader,
1227}
1228
1229impl MultiLeaderBuilder {
1230 pub fn new() -> Self {
1232 Self {
1233 multileader: MultiLeader::new(),
1234 }
1235 }
1236
1237 pub fn text(mut self, text: &str, location: Vector3) -> Self {
1239 self.multileader.set_text_content(text, location);
1240 self
1241 }
1242
1243 pub fn block(mut self, block_handle: Handle, location: Vector3) -> Self {
1245 self.multileader.set_block_content(block_handle, location);
1246 self
1247 }
1248
1249 pub fn no_content(mut self) -> Self {
1251 self.multileader.content_type = LeaderContentType::None;
1252 self
1253 }
1254
1255 pub fn leader_line(mut self, points: Vec<Vector3>) -> Self {
1257 if self.multileader.context.leader_roots.is_empty() {
1258 self.multileader.add_leader_root();
1259 }
1260 let root = self.multileader.context.leader_roots.last_mut().unwrap();
1261 root.create_line(points);
1262 self
1263 }
1264
1265 pub fn new_root(mut self) -> Self {
1267 self.multileader.add_leader_root();
1268 self
1269 }
1270
1271 pub fn path_type(mut self, path_type: MultiLeaderPathType) -> Self {
1273 self.multileader.path_type = path_type;
1274 self
1275 }
1276
1277 pub fn arrowhead_size(mut self, size: f64) -> Self {
1279 self.multileader.arrowhead_size = size;
1280 self.multileader.context.arrowhead_size = size;
1281 self
1282 }
1283
1284 pub fn text_height(mut self, height: f64) -> Self {
1286 self.multileader.text_height = height;
1287 self.multileader.context.text_height = height;
1288 self
1289 }
1290
1291 pub fn text_frame(mut self, frame: bool) -> Self {
1293 self.multileader.text_frame = frame;
1294 self
1295 }
1296
1297 pub fn line_color(mut self, color: Color) -> Self {
1299 self.multileader.line_color = color;
1300 self
1301 }
1302
1303 pub fn text_color(mut self, color: Color) -> Self {
1305 self.multileader.text_color = color;
1306 self.multileader.context.text_color = color;
1307 self
1308 }
1309
1310 pub fn landing(mut self, enable: bool) -> Self {
1312 self.multileader.enable_landing = enable;
1313 self
1314 }
1315
1316 pub fn dogleg_length(mut self, length: f64) -> Self {
1318 self.multileader.dogleg_length = length;
1319 self
1320 }
1321
1322 pub fn scale(mut self, scale: f64) -> Self {
1324 self.multileader.scale_factor = scale;
1325 self.multileader.context.scale_factor = scale;
1326 self
1327 }
1328
1329 pub fn build(self) -> MultiLeader {
1331 self.multileader
1332 }
1333}
1334
1335impl Default for MultiLeaderBuilder {
1336 fn default() -> Self {
1337 Self::new()
1338 }
1339}
1340
1341#[cfg(test)]
1346mod tests {
1347 use super::*;
1348
1349 #[test]
1350 fn test_multileader_creation() {
1351 let mleader = MultiLeader::new();
1352 assert_eq!(mleader.content_type, LeaderContentType::MText);
1353 assert!(mleader.enable_landing);
1354 assert!(mleader.enable_dogleg);
1355 assert_eq!(mleader.leader_root_count(), 0);
1356 }
1357
1358 #[test]
1359 fn test_multileader_with_text() {
1360 let points = vec![
1361 Vector3::new(0.0, 0.0, 0.0),
1362 Vector3::new(5.0, 5.0, 0.0),
1363 ];
1364 let mleader = MultiLeader::with_text("Note", Vector3::new(10.0, 10.0, 0.0), points);
1365
1366 assert_eq!(mleader.content_type, LeaderContentType::MText);
1367 assert_eq!(mleader.text(), Some("Note"));
1368 assert_eq!(mleader.leader_root_count(), 1);
1369 assert_eq!(mleader.total_leader_line_count(), 1);
1370 }
1371
1372 #[test]
1373 fn test_multileader_add_leader_root() {
1374 let mut mleader = MultiLeader::new();
1375 let root = mleader.add_leader_root();
1376 root.create_line(vec![Vector3::ZERO, Vector3::new(1.0, 1.0, 0.0)]);
1377 root.create_line(vec![Vector3::new(0.0, 1.0, 0.0), Vector3::new(1.0, 1.0, 0.0)]);
1378
1379 assert_eq!(mleader.leader_root_count(), 1);
1380 assert_eq!(mleader.total_leader_line_count(), 2);
1381 }
1382
1383 #[test]
1384 fn test_leader_line() {
1385 let mut line = LeaderLine::new(0);
1386 line.add_point(Vector3::new(0.0, 0.0, 0.0));
1387 line.add_point(Vector3::new(3.0, 4.0, 0.0));
1388
1389 assert_eq!(line.point_count(), 2);
1390 assert_eq!(line.start_point(), Some(Vector3::new(0.0, 0.0, 0.0)));
1391 assert_eq!(line.end_point(), Some(Vector3::new(3.0, 4.0, 0.0)));
1392 assert!((line.length() - 5.0).abs() < 1e-10);
1393 }
1394
1395 #[test]
1396 fn test_multileader_translate() {
1397 let mut mleader = MultiLeader::with_text(
1398 "Note",
1399 Vector3::new(10.0, 10.0, 0.0),
1400 vec![Vector3::ZERO, Vector3::new(5.0, 5.0, 0.0)],
1401 );
1402
1403 mleader.translate(Vector3::new(5.0, 5.0, 0.0));
1404
1405 assert_eq!(mleader.context.text_location, Vector3::new(15.0, 15.0, 0.0));
1406 let root = &mleader.context.leader_roots[0];
1407 let line = &root.lines[0];
1408 assert_eq!(line.points[0], Vector3::new(5.0, 5.0, 0.0));
1409 assert_eq!(line.points[1], Vector3::new(10.0, 10.0, 0.0));
1410 }
1411
1412 #[test]
1413 fn test_multileader_bounding_box() {
1414 let mleader = MultiLeader::with_text(
1415 "Note",
1416 Vector3::new(10.0, 10.0, 0.0),
1417 vec![
1418 Vector3::new(0.0, 0.0, 0.0),
1419 Vector3::new(5.0, 5.0, 0.0),
1420 ],
1421 );
1422
1423 let bbox = mleader.bounding_box().unwrap();
1424 assert_eq!(bbox.0, Vector3::new(0.0, 0.0, 0.0));
1425 assert_eq!(bbox.1, Vector3::new(10.0, 10.0, 0.0));
1426 }
1427
1428 #[test]
1429 fn test_content_types() {
1430 assert_eq!(LeaderContentType::from(0), LeaderContentType::None);
1431 assert_eq!(LeaderContentType::from(1), LeaderContentType::Block);
1432 assert_eq!(LeaderContentType::from(2), LeaderContentType::MText);
1433 assert_eq!(LeaderContentType::from(3), LeaderContentType::Tolerance);
1434 }
1435
1436 #[test]
1437 fn test_path_types() {
1438 assert_eq!(MultiLeaderPathType::from(0), MultiLeaderPathType::Invisible);
1439 assert_eq!(MultiLeaderPathType::from(1), MultiLeaderPathType::StraightLineSegments);
1440 assert_eq!(MultiLeaderPathType::from(2), MultiLeaderPathType::Spline);
1441 }
1442
1443 #[test]
1444 fn test_text_attachment_types() {
1445 assert_eq!(TextAttachmentType::from(0), TextAttachmentType::TopOfTopLine);
1446 assert_eq!(TextAttachmentType::from(2), TextAttachmentType::MiddleOfText);
1447 assert_eq!(TextAttachmentType::from(9), TextAttachmentType::CenterOfText);
1448 }
1449
1450 #[test]
1451 fn test_builder() {
1452 let mleader = MultiLeaderBuilder::new()
1453 .text("Note", Vector3::new(10.0, 10.0, 0.0))
1454 .leader_line(vec![Vector3::ZERO, Vector3::new(5.0, 5.0, 0.0)])
1455 .arrowhead_size(0.25)
1456 .text_height(0.2)
1457 .text_frame(true)
1458 .scale(2.0)
1459 .build();
1460
1461 assert_eq!(mleader.text(), Some("Note"));
1462 assert_eq!(mleader.arrowhead_size, 0.25);
1463 assert_eq!(mleader.text_height, 0.2);
1464 assert!(mleader.text_frame);
1465 assert_eq!(mleader.scale_factor, 2.0);
1466 }
1467
1468 #[test]
1469 fn test_property_override_flags() {
1470 let flags = MultiLeaderPropertyOverrideFlags::PATH_TYPE
1471 | MultiLeaderPropertyOverrideFlags::LINE_COLOR
1472 | MultiLeaderPropertyOverrideFlags::TEXT_HEIGHT;
1473
1474 assert!(flags.contains(MultiLeaderPropertyOverrideFlags::PATH_TYPE));
1475 assert!(flags.contains(MultiLeaderPropertyOverrideFlags::LINE_COLOR));
1476 assert!(flags.contains(MultiLeaderPropertyOverrideFlags::TEXT_HEIGHT));
1477 assert!(!flags.contains(MultiLeaderPropertyOverrideFlags::ARROWHEAD));
1478 }
1479
1480 #[test]
1481 fn test_leader_line_override_flags() {
1482 let flags = LeaderLinePropertyOverrideFlags::LINE_COLOR
1483 | LeaderLinePropertyOverrideFlags::ARROWHEAD;
1484
1485 assert!(flags.contains(LeaderLinePropertyOverrideFlags::LINE_COLOR));
1486 assert!(flags.contains(LeaderLinePropertyOverrideFlags::ARROWHEAD));
1487 assert!(!flags.contains(LeaderLinePropertyOverrideFlags::PATH_TYPE));
1488 }
1489
1490 #[test]
1491 fn test_block_attribute() {
1492 let attr = BlockAttribute::new("Value");
1493 assert_eq!(attr.text, "Value");
1494 assert_eq!(attr.index, 0);
1495 assert_eq!(attr.width, 0.0);
1496 }
1497
1498 #[test]
1499 fn test_annot_context_defaults() {
1500 let ctx = MultiLeaderAnnotContext::new();
1501 assert_eq!(ctx.scale_factor, 1.0);
1502 assert_eq!(ctx.text_height, 0.18);
1503 assert!(!ctx.has_text_contents);
1504 assert!(!ctx.has_block_contents);
1505 assert_eq!(ctx.leader_roots.len(), 0);
1506 }
1507}
1508