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
//! 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, Color, Handle, LineWeight, Transform, Transparency, 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 handle(&self) -> Handle {
self.common.handle
}
fn set_handle(&mut self, handle: Handle) {
self.common.handle = handle;
}
fn layer(&self) -> &str {
&self.common.layer
}
fn set_layer(&mut self, layer: String) {
self.common.layer = layer;
}
fn color(&self) -> Color {
self.common.color
}
fn set_color(&mut self, color: Color) {
self.common.color = color;
}
fn line_weight(&self) -> LineWeight {
self.common.line_weight
}
fn set_line_weight(&mut self, weight: LineWeight) {
self.common.line_weight = weight;
}
fn transparency(&self) -> Transparency {
self.common.transparency
}
fn set_transparency(&mut self, transparency: Transparency) {
self.common.transparency = transparency;
}
fn is_invisible(&self) -> bool {
self.common.invisible
}
fn set_invisible(&mut self, invisible: bool) {
self.common.invisible = invisible;
}
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) {
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];
}
}