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
//! Drawing-view border entity (`AcDbViewBorder`, DXF class "DRAWINGVIEW").
//!
//! The border of a Model-Documentation drawing view. Its paper-space rectangle,
//! view scale and the reference to the view's *active* viewport (the entity
//! carrying the real camera) are decoded and encoded as native semantic fields.
//!
//! The border itself is a non-plotting aid — it is not drawn — but its
//! rectangle gives each view's true paper placement, and its viewport link is
//! the last hop of the section-mark viewing-direction chain.
use super::{Entity, EntityCommon};
use crate::types::{BoundingBox3D, Handle, Transform, Vector3};
/// A Model-Documentation drawing-view border (`AcDbViewBorder`).
///
/// All coordinates are layout paper-space. Verified: `max − min` equals the
/// view's template-viewport size, `center` is exactly the rectangle midpoint
/// (stored redundantly in the record), and `scale` equals the template/active
/// viewport height ratio.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ViewBorder {
/// Common entity data (handle, layer, color, …).
pub common: EntityCommon,
/// `AcDbViewBorder` version (group 70).
pub version: i16,
/// Border rectangle minimum corner.
pub min: [f64; 2],
/// Border rectangle maximum corner.
pub max: [f64; 2],
/// View centre point (the rectangle midpoint).
pub center: [f64; 2],
/// View scale value (group 40).
pub scale: f64,
/// View rotation angle in radians (second group 40).
pub rotation_angle: f64,
/// The view's *active* viewport entity (the border's first object-specific
/// handle reference) — carries the real camera (`view_direction`, twist).
pub active_viewport: Handle,
/// Associated `SCALE` object (group 340).
pub scale_handle: Handle,
}
impl ViewBorder {
/// Create an empty view border.
pub fn new() -> Self {
ViewBorder {
common: EntityCommon::new(),
version: 0,
min: [0.0; 2],
max: [0.0; 2],
center: [0.0; 2],
scale: 1.0,
rotation_angle: 0.0,
active_viewport: Handle::NULL,
scale_handle: Handle::NULL,
}
}
}
impl Default for ViewBorder {
fn default() -> Self {
Self::new()
}
}
impl Entity for ViewBorder {
fn common(&self) -> &super::EntityCommon {
&self.common
}
fn common_mut(&mut self) -> &mut super::EntityCommon {
&mut self.common
}
fn bounding_box(&self) -> BoundingBox3D {
BoundingBox3D {
min: Vector3::new(self.min[0], self.min[1], 0.0),
max: Vector3::new(self.max[0], self.max[1], 0.0),
}
}
fn translate(&mut self, offset: Vector3) {
self.min[0] += offset.x;
self.min[1] += offset.y;
self.max[0] += offset.x;
self.max[1] += offset.y;
self.center[0] += offset.x;
self.center[1] += offset.y;
}
fn entity_type(&self) -> &'static str {
"DRAWINGVIEW"
}
fn apply_transform(&mut self, transform: &Transform) {
self.common.raw_record = None;
let corners = [
Vector3::new(self.min[0], self.min[1], 0.0),
Vector3::new(self.max[0], self.min[1], 0.0),
Vector3::new(self.max[0], self.max[1], 0.0),
Vector3::new(self.min[0], self.max[1], 0.0),
]
.map(|point| transform.apply(point));
let mut min = [f64::INFINITY; 2];
let mut max = [f64::NEG_INFINITY; 2];
for point in corners {
min[0] = min[0].min(point.x);
min[1] = min[1].min(point.y);
max[0] = max[0].max(point.x);
max[1] = max[1].max(point.y);
}
let center = transform.apply(Vector3::new(self.center[0], self.center[1], 0.0));
self.min = min;
self.max = max;
self.center = [center.x, center.y];
super::transform::rotate_stored_angle(&mut self.rotation_angle, transform);
}
}