forked from 1b-agent/opencadstudio-upstream
fix(styles): apply active creation defaults
Resolve style properties before editors and previews open. Use absolute annotation multipliers for style-driven objects. Refs #401 Refs #431
This commit is contained in:
1 parent
53cf31f33d
commit
de2707a23e
14 files changed
+676
-129
No files matched your search
+53
-3
@@ -49,7 +49,11 @@ impl OpenCADStudio {
|
||||
// quick leader-plus-annotation operation.
|
||||
"LEADER" | "QLEADER" => {
|
||||
use crate::modules::annotate::leader_cmd::LeaderCommand;
|
||||
let new_cmd = LeaderCommand::new();
|
||||
let defaults = crate::scene::creation_style::current_dimension_defaults(
|
||||
&self.tabs[i].scene.document,
|
||||
);
|
||||
let multiplier = self.tabs[i].scene.creation_annotation_multiplier();
|
||||
let new_cmd = LeaderCommand::with_defaults(defaults, multiplier);
|
||||
self.command_line.push_info(&new_cmd.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(new_cmd));
|
||||
}
|
||||
@@ -486,7 +490,31 @@ impl OpenCADStudio {
|
||||
|
||||
"MLEADER" => {
|
||||
use crate::modules::annotate::mleader_cmd::MLeaderCommand;
|
||||
let new_cmd = MLeaderCommand::new();
|
||||
let name = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.header
|
||||
.current_mleader_style_name
|
||||
.clone();
|
||||
let style = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.objects
|
||||
.iter()
|
||||
.find_map(|(handle, object)| match object {
|
||||
acadrust::objects::ObjectType::MultiLeaderStyle(style)
|
||||
if style.name.eq_ignore_ascii_case(&name) =>
|
||||
{
|
||||
let mut style = style.clone();
|
||||
style.handle = *handle;
|
||||
Some(style)
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
let multiplier = self.tabs[i].scene.creation_annotation_multiplier();
|
||||
let new_cmd = style.map_or_else(MLeaderCommand::new, |style| {
|
||||
MLeaderCommand::with_style(style, multiplier)
|
||||
});
|
||||
self.command_line.push_info(&new_cmd.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(new_cmd));
|
||||
}
|
||||
@@ -500,7 +528,29 @@ impl OpenCADStudio {
|
||||
|
||||
"TABLE" => {
|
||||
use crate::modules::annotate::table_cmd::TableCommand;
|
||||
let cmd = TableCommand::new();
|
||||
let name = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.header
|
||||
.current_table_style_name
|
||||
.clone();
|
||||
let style = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.objects
|
||||
.iter()
|
||||
.find_map(|(handle, object)| match object {
|
||||
acadrust::objects::ObjectType::TableStyle(style)
|
||||
if style.name.eq_ignore_ascii_case(&name) =>
|
||||
{
|
||||
Some((*handle, style.clone()))
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
let multiplier = self.tabs[i].scene.creation_annotation_multiplier();
|
||||
let cmd = style.as_ref().map_or_else(TableCommand::new, |(handle, style)| {
|
||||
TableCommand::with_style(*handle, style, multiplier)
|
||||
});
|
||||
self.command_line.push_info(&cmd.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
||||
}
|
||||
|
||||
@@ -13,8 +13,28 @@ impl OpenCADStudio {
|
||||
|
||||
"MLINE" => {
|
||||
use crate::modules::draw::draw::mline::MlineCommand;
|
||||
let style = self.tabs[i].scene.document.header.multiline_style.clone();
|
||||
let cmd_obj = MlineCommand::with_style(style);
|
||||
let style_name = self.tabs[i].scene.document.header.multiline_style.clone();
|
||||
let style = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.objects
|
||||
.iter()
|
||||
.find_map(|(handle, object)| match object {
|
||||
acadrust::objects::ObjectType::MLineStyle(style)
|
||||
if style.name.eq_ignore_ascii_case(&style_name) =>
|
||||
{
|
||||
Some((*handle, style.elements.len()))
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
let (style_handle, element_count) = style
|
||||
.map(|(handle, count)| (Some(handle), count))
|
||||
.unwrap_or((None, 2));
|
||||
let cmd_obj = MlineCommand::with_style(
|
||||
style_name,
|
||||
style_handle,
|
||||
element_count,
|
||||
);
|
||||
self.command_line.push_info(&cmd_obj.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(cmd_obj));
|
||||
}
|
||||
@@ -47,7 +67,15 @@ impl OpenCADStudio {
|
||||
|
||||
"ATTDEF" => {
|
||||
use crate::modules::draw::draw::attdef::AttdefCommand;
|
||||
let cmd = AttdefCommand::new();
|
||||
let defaults = crate::scene::creation_style::current_text_defaults(
|
||||
&self.tabs[i].scene.document,
|
||||
);
|
||||
let cmd = AttdefCommand::with_text_defaults(
|
||||
defaults.height,
|
||||
defaults.style_name,
|
||||
defaults.width_factor,
|
||||
defaults.oblique_angle,
|
||||
);
|
||||
self.command_line.push_info(&cmd.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(cmd));
|
||||
}
|
||||
@@ -1049,7 +1077,11 @@ impl OpenCADStudio {
|
||||
// ── Annotate commands ──────────────────────────────────────────
|
||||
"TEXT" => {
|
||||
use crate::modules::annotate::text::TextCommand;
|
||||
let new_cmd = TextCommand::new();
|
||||
let height = crate::scene::creation_style::current_text_defaults(
|
||||
&self.tabs[i].scene.document,
|
||||
)
|
||||
.height;
|
||||
let new_cmd = TextCommand::with_height(height);
|
||||
self.command_line.push_info(&new_cmd.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(new_cmd));
|
||||
}
|
||||
@@ -1080,7 +1112,11 @@ impl OpenCADStudio {
|
||||
|
||||
"MTEXT" => {
|
||||
use crate::modules::annotate::mtext::MTextCommand;
|
||||
let new_cmd = MTextCommand::new();
|
||||
let height = crate::scene::creation_style::current_text_defaults(
|
||||
&self.tabs[i].scene.document,
|
||||
)
|
||||
.height;
|
||||
let new_cmd = MTextCommand::with_height(height);
|
||||
self.command_line.push_info(&new_cmd.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(new_cmd));
|
||||
}
|
||||
|
||||
+4
-68
@@ -1848,74 +1848,10 @@ impl OpenCADStudio {
|
||||
entity.common_mut().linetype_scale = celtscale;
|
||||
}
|
||||
|
||||
// A new dimension inherits the document's current dimension style
|
||||
// (DIMSTYLE) instead of staying at the entity "Standard" default. Only
|
||||
// fill in when still at the default so an explicitly-styled dimension
|
||||
// is preserved. See #92.
|
||||
if let acadrust::EntityType::Dimension(ref mut d) = entity {
|
||||
let cur = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.header
|
||||
.current_dimstyle_name
|
||||
.clone();
|
||||
let s = d.base().style_name.clone();
|
||||
if (s.is_empty() || s.eq_ignore_ascii_case("Standard")) && !cur.is_empty() {
|
||||
d.base_mut().style_name = cur;
|
||||
}
|
||||
}
|
||||
|
||||
// MultiLeader / Table inherit the document's current style (#92). These
|
||||
// styles live in the objects dictionary, so resolve the current style
|
||||
// name to its object handle. Left untouched when the command already
|
||||
// assigned a style or no matching style object exists.
|
||||
match &mut entity {
|
||||
acadrust::EntityType::MultiLeader(ml) if ml.style_handle.is_none() => {
|
||||
let name = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.header
|
||||
.current_mleader_style_name
|
||||
.clone();
|
||||
if !name.is_empty() {
|
||||
let found =
|
||||
self.tabs[i].scene.document.objects.iter().find_map(|(h, o)| match o {
|
||||
acadrust::objects::ObjectType::MultiLeaderStyle(s)
|
||||
if s.name.eq_ignore_ascii_case(&name) =>
|
||||
{
|
||||
Some((*h, s.clone()))
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
if let Some((h, s)) = found {
|
||||
debug_assert_eq!(h, s.handle);
|
||||
crate::scene::annotative::apply_mleader_style(ml, &s);
|
||||
}
|
||||
}
|
||||
}
|
||||
acadrust::EntityType::Table(t) if t.table_style_handle.is_none() => {
|
||||
let name = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.header
|
||||
.current_table_style_name
|
||||
.clone();
|
||||
if !name.is_empty() {
|
||||
t.table_style_handle =
|
||||
self.tabs[i].scene.document.objects.iter().find_map(|(h, o)| {
|
||||
match o {
|
||||
acadrust::objects::ObjectType::TableStyle(s)
|
||||
if s.name.eq_ignore_ascii_case(&name) =>
|
||||
{
|
||||
Some(*h)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
crate::scene::creation_style::apply_current_creation_styles(
|
||||
&self.tabs[i].scene.document,
|
||||
&mut entity,
|
||||
);
|
||||
|
||||
let text_style_annotative = match &entity {
|
||||
acadrust::EntityType::Text(text) => {
|
||||
|
||||
@@ -1581,9 +1581,8 @@ fn tessellate_dimension_inner(
|
||||
}
|
||||
let style = effective_style.as_ref();
|
||||
|
||||
// DIMSCALE rule:
|
||||
// dimstyle.dimscale > 0 → final multiplier; ignore anno_scale.
|
||||
// dimstyle.dimscale == 0 → annotative: use anno_scale (= 1/vp_scale).
|
||||
// A positive style scale is fixed. A zero style scale uses the multiplier
|
||||
// resolved by the scene for the current annotation or viewport context.
|
||||
let dim_scale = style
|
||||
.map(|s| {
|
||||
if s.dimscale > 1e-6 {
|
||||
|
||||
@@ -34,11 +34,36 @@ pub fn tool() -> ToolDef {
|
||||
pub struct LeaderCommand {
|
||||
verts: Vec<DVec3>,
|
||||
ucs: Mat4,
|
||||
dimension_style: String,
|
||||
text_style: String,
|
||||
text_height: f64,
|
||||
display_scale: f64,
|
||||
gap: f64,
|
||||
arrow_size: f64,
|
||||
annotative: bool,
|
||||
}
|
||||
|
||||
impl LeaderCommand {
|
||||
pub fn new() -> Self {
|
||||
Self { verts: Vec::new(), ucs: Mat4::IDENTITY }
|
||||
pub fn with_defaults(
|
||||
defaults: crate::scene::creation_style::DimensionCreationDefaults,
|
||||
annotation_multiplier: f64,
|
||||
) -> Self {
|
||||
let display_scale = if defaults.annotative {
|
||||
annotation_multiplier
|
||||
} else {
|
||||
defaults.scale
|
||||
};
|
||||
Self {
|
||||
verts: Vec::new(),
|
||||
ucs: Mat4::IDENTITY,
|
||||
dimension_style: defaults.style_name,
|
||||
text_style: defaults.text_style_name,
|
||||
text_height: defaults.text_height,
|
||||
display_scale,
|
||||
gap: defaults.gap,
|
||||
arrow_size: defaults.arrow_size,
|
||||
annotative: defaults.annotative,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +99,30 @@ impl CadCommand for LeaderCommand {
|
||||
}
|
||||
// Place the leader plus an empty MText annotation, link them, then open
|
||||
// the in-place MText editor so the user types the annotation text.
|
||||
let leader = build_leader(&self.verts, self.ucs);
|
||||
let (anchor, attach) = annotation_anchor(&self.verts, leader.text_height, self.ucs);
|
||||
let mtext = build_mtext("", anchor, leader.text_height, attach, self.ucs);
|
||||
let leader = build_leader(
|
||||
&self.verts,
|
||||
self.ucs,
|
||||
&self.dimension_style,
|
||||
self.text_height,
|
||||
self.gap,
|
||||
self.arrow_size,
|
||||
);
|
||||
let displayed_height = self.text_height * self.display_scale;
|
||||
let (anchor, attach) = annotation_anchor(&self.verts, displayed_height, self.ucs);
|
||||
let mtext_height = if self.annotative {
|
||||
self.text_height
|
||||
} else {
|
||||
displayed_height
|
||||
};
|
||||
let mtext = build_mtext(
|
||||
"",
|
||||
anchor,
|
||||
mtext_height,
|
||||
attach,
|
||||
self.ucs,
|
||||
&self.text_style,
|
||||
self.annotative,
|
||||
);
|
||||
CmdResult::CommitManyAndEditText {
|
||||
entities: vec![EntityType::Leader(leader), EntityType::MText(mtext)],
|
||||
edit_index: 1,
|
||||
@@ -93,7 +139,10 @@ impl CadCommand for LeaderCommand {
|
||||
}
|
||||
let mut pts: Vec<Vec3> = self.verts.iter().map(|p| p.as_vec3()).collect();
|
||||
pts.push(pt.as_vec3());
|
||||
Some(preview_wire(&pts))
|
||||
Some(preview_wire(
|
||||
&pts,
|
||||
(self.arrow_size * self.display_scale) as f32,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,10 +152,21 @@ fn dv3(p: DVec3) -> Vector3 {
|
||||
Vector3::new(p.x, p.y, p.z)
|
||||
}
|
||||
|
||||
fn build_leader(verts: &[DVec3], ucs: Mat4) -> Leader {
|
||||
fn build_leader(
|
||||
verts: &[DVec3],
|
||||
ucs: Mat4,
|
||||
dimension_style: &str,
|
||||
text_height: f64,
|
||||
gap: f64,
|
||||
arrow_size: f64,
|
||||
) -> Leader {
|
||||
let mut l = Leader::from_vertices(verts.iter().map(|p| dv3(*p)).collect());
|
||||
l.creation_type = LeaderCreationType::WithText;
|
||||
l.hookline_enabled = true;
|
||||
l.dimension_style = dimension_style.to_string();
|
||||
l.text_height = text_height;
|
||||
l.dimension_gap = gap;
|
||||
l.arrow_size = arrow_size;
|
||||
// The hookline / text read along the UCS X axis (DXF "horizontal direction
|
||||
// for text"); the renderer uses it instead of world horizontal.
|
||||
let ux = ucs.transform_vector3(Vec3::X).normalize_or(Vec3::X);
|
||||
@@ -143,11 +203,15 @@ fn build_mtext(
|
||||
height: f64,
|
||||
attach: AttachmentPoint,
|
||||
ucs: Mat4,
|
||||
text_style: &str,
|
||||
annotative: bool,
|
||||
) -> MText {
|
||||
let mut m = MText::new();
|
||||
m.value = text.to_string();
|
||||
m.insertion_point = dv3(pos);
|
||||
m.height = height;
|
||||
m.style = text_style.to_string();
|
||||
m.is_annotative = annotative;
|
||||
m.attachment_point = attach;
|
||||
// Text reads along the UCS X axis.
|
||||
let ux = ucs.transform_vector3(Vec3::X);
|
||||
@@ -155,10 +219,10 @@ fn build_mtext(
|
||||
m
|
||||
}
|
||||
|
||||
fn preview_wire(pts: &[Vec3]) -> WireModel {
|
||||
fn preview_wire(pts: &[Vec3], arrow_size: f32) -> WireModel {
|
||||
let mut points: Vec<[f32; 3]> = pts.iter().map(|p| [p.x, p.y, p.z]).collect();
|
||||
if pts.len() >= 2 {
|
||||
let [w1, w2] = arrowhead_wings(pts[0], pts[1], 2.5);
|
||||
let [w1, w2] = arrowhead_wings(pts[0], pts[1], arrow_size);
|
||||
points.push([f32::NAN; 3]);
|
||||
points.push([w1.x, w1.y, w1.z]);
|
||||
points.push([pts[0].x, pts[0].y, pts[0].z]);
|
||||
|
||||
@@ -29,11 +29,35 @@ pub fn tool() -> ToolDef {
|
||||
pub struct MLeaderCommand {
|
||||
verts: Vec<DVec3>,
|
||||
ucs: Mat4,
|
||||
style: Option<acadrust::objects::MultiLeaderStyle>,
|
||||
display_scale: f64,
|
||||
}
|
||||
|
||||
impl MLeaderCommand {
|
||||
pub fn new() -> Self {
|
||||
Self { verts: Vec::new(), ucs: Mat4::IDENTITY }
|
||||
Self {
|
||||
verts: Vec::new(),
|
||||
ucs: Mat4::IDENTITY,
|
||||
style: None,
|
||||
display_scale: 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_style(
|
||||
style: acadrust::objects::MultiLeaderStyle,
|
||||
annotation_multiplier: f64,
|
||||
) -> Self {
|
||||
let display_scale = if style.is_annotative {
|
||||
annotation_multiplier
|
||||
} else {
|
||||
style.scale_factor
|
||||
};
|
||||
Self {
|
||||
verts: Vec::new(),
|
||||
ucs: Mat4::IDENTITY,
|
||||
style: Some(style),
|
||||
display_scale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +93,13 @@ impl CadCommand for MLeaderCommand {
|
||||
}
|
||||
// Place the leader with empty text, then open the in-place MText editor
|
||||
// so the user types the annotation into the rich editor.
|
||||
let ml = build_mleader("", &self.verts, self.ucs);
|
||||
let ml = build_mleader(
|
||||
"",
|
||||
&self.verts,
|
||||
self.ucs,
|
||||
self.style.as_ref(),
|
||||
self.display_scale,
|
||||
);
|
||||
CmdResult::CommitAndEditText(EntityType::MultiLeader(ml))
|
||||
}
|
||||
|
||||
@@ -84,7 +114,12 @@ impl CadCommand for MLeaderCommand {
|
||||
// Preview / rubber-band is GPU screen-space: downcast to f32 here.
|
||||
let mut pts: Vec<Vec3> = self.verts.iter().map(|p| p.as_vec3()).collect();
|
||||
pts.push(pt.as_vec3());
|
||||
Some(preview_wire(&pts))
|
||||
let arrow_size = self
|
||||
.style
|
||||
.as_ref()
|
||||
.map_or(2.5, |style| style.arrowhead_size)
|
||||
* self.display_scale;
|
||||
Some(preview_wire(&pts, arrow_size as f32))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +129,13 @@ fn v3(p: DVec3) -> Vector3 {
|
||||
Vector3::new(p.x, p.y, p.z)
|
||||
}
|
||||
|
||||
fn build_mleader(text: &str, verts: &[DVec3], ucs: Mat4) -> MultiLeader {
|
||||
fn build_mleader(
|
||||
text: &str,
|
||||
verts: &[DVec3],
|
||||
ucs: Mat4,
|
||||
style: Option<&acadrust::objects::MultiLeaderStyle>,
|
||||
display_scale: f64,
|
||||
) -> MultiLeader {
|
||||
// Last vertex = content/text location; remaining = leader line points
|
||||
let (leader_pts, content_pt) = verts.split_at(verts.len() - 1);
|
||||
let content_pt = content_pt[0];
|
||||
@@ -103,14 +144,22 @@ fn build_mleader(text: &str, verts: &[DVec3], ucs: Mat4) -> MultiLeader {
|
||||
let content_v3 = v3(content_pt);
|
||||
|
||||
let mut ml = MultiLeader::with_text(text, content_v3, leader_v3);
|
||||
if let Some(style) = style {
|
||||
crate::scene::annotative::apply_mleader_style(&mut ml, style);
|
||||
} else {
|
||||
ml.text_height = 2.5;
|
||||
ml.context.text_height = 2.5;
|
||||
ml.arrowhead_size = 2.5;
|
||||
ml.context.arrowhead_size = 2.5;
|
||||
ml.dogleg_length = 2.5;
|
||||
}
|
||||
|
||||
// Match Leader entity defaults
|
||||
ml.text_height = 2.5;
|
||||
ml.context.text_height = 2.5;
|
||||
ml.arrowhead_size = 2.5;
|
||||
ml.dogleg_length = 2.5;
|
||||
|
||||
const DOGLEG: f64 = 2.5;
|
||||
let landing_distance = ml.dogleg_length * display_scale;
|
||||
let landing_gap = ml.context.landing_gap * display_scale;
|
||||
ml.context.scale_factor = display_scale;
|
||||
ml.context.text_height = ml.text_height * display_scale;
|
||||
ml.context.arrowhead_size = ml.arrowhead_size * display_scale;
|
||||
ml.context.landing_gap = landing_gap;
|
||||
// "Horizontal" landing + text run along the active UCS X axis (identity =
|
||||
// world), so the annotation reads square to the user's coordinate system.
|
||||
let ux = ucs.transform_vector3(Vec3::X).normalize_or(Vec3::X);
|
||||
@@ -130,22 +179,22 @@ fn build_mleader(text: &str, verts: &[DVec3], ucs: Mat4) -> MultiLeader {
|
||||
// the text along the UCS X axis.
|
||||
root.direction = Vector3::new(landing.x as f64, landing.y as f64, 0.0);
|
||||
root.connection_point = content_v3;
|
||||
root.landing_distance = DOGLEG;
|
||||
root.landing_distance = landing_distance;
|
||||
}
|
||||
|
||||
// Seed the text one landing-length past the leader end, on the side the
|
||||
// user dragged toward, offset along the UCS X axis.
|
||||
let off = landing * DOGLEG as f32;
|
||||
let off = landing * (landing_distance + landing_gap) as f32;
|
||||
ml.context.text_location =
|
||||
Vector3::new(content_v3.x + off.x as f64, content_v3.y + off.y as f64, content_v3.z);
|
||||
|
||||
ml
|
||||
}
|
||||
|
||||
fn preview_wire(pts: &[Vec3]) -> WireModel {
|
||||
fn preview_wire(pts: &[Vec3], arrow_size: f32) -> WireModel {
|
||||
let mut points: Vec<[f32; 3]> = pts.iter().map(|p| [p.x, p.y, p.z]).collect();
|
||||
if pts.len() >= 2 {
|
||||
let [w1, w2] = arrowhead_wings(pts[0], pts[1], 2.5);
|
||||
let [w1, w2] = arrowhead_wings(pts[0], pts[1], arrow_size);
|
||||
points.push([f32::NAN; 3]);
|
||||
points.push([w1.x, w1.y, w1.z]);
|
||||
points.push([pts[0].x, pts[0].y, pts[0].z]);
|
||||
|
||||
@@ -21,12 +21,14 @@ enum Step {
|
||||
|
||||
pub struct MTextCommand {
|
||||
step: Step,
|
||||
height: f64,
|
||||
}
|
||||
|
||||
impl MTextCommand {
|
||||
pub fn new() -> Self {
|
||||
pub fn with_height(height: f64) -> Self {
|
||||
Self {
|
||||
step: Step::InsertPoint,
|
||||
height,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +50,7 @@ impl CadCommand for MTextCommand {
|
||||
pos: pt,
|
||||
handle: None,
|
||||
initial: String::new(),
|
||||
height: 0.25,
|
||||
height: self.height,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,12 +41,46 @@ enum Step {
|
||||
|
||||
pub struct TableCommand {
|
||||
step: Step,
|
||||
style_handle: Option<acadrust::Handle>,
|
||||
column_width: f64,
|
||||
row_height: f64,
|
||||
preview_scale: f64,
|
||||
}
|
||||
|
||||
impl TableCommand {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
step: Step::Columns,
|
||||
style_handle: None,
|
||||
column_width: COL_WIDTH,
|
||||
row_height: ROW_HEIGHT,
|
||||
preview_scale: 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_style(
|
||||
style_handle: acadrust::Handle,
|
||||
style: &acadrust::objects::TableStyle,
|
||||
annotation_multiplier: f64,
|
||||
) -> Self {
|
||||
let text_height = style
|
||||
.data_row_style
|
||||
.text_height
|
||||
.max(style.header_row_style.text_height)
|
||||
.max(style.title_row_style.text_height)
|
||||
.max(1.0e-6);
|
||||
let row_height = text_height * 1.5 + style.vertical_margin * 2.0;
|
||||
let column_width = text_height * 8.0 + style.horizontal_margin * 2.0;
|
||||
Self {
|
||||
step: Step::Columns,
|
||||
style_handle: Some(style_handle),
|
||||
column_width,
|
||||
row_height,
|
||||
preview_scale: if style.annotative {
|
||||
annotation_multiplier
|
||||
} else {
|
||||
1.0
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,11 +164,12 @@ impl CadCommand for TableCommand {
|
||||
fn on_point(&mut self, pt: DVec3) -> CmdResult {
|
||||
if let Step::Insertion { cols, rows } = self.step {
|
||||
let ins = Vector3::new(pt.x, pt.y, pt.z);
|
||||
let table = TableBuilder::new(rows, cols)
|
||||
let mut table = TableBuilder::new(rows, cols)
|
||||
.at(ins)
|
||||
.row_height(ROW_HEIGHT)
|
||||
.column_width(COL_WIDTH)
|
||||
.row_height(self.row_height)
|
||||
.column_width(self.column_width)
|
||||
.build();
|
||||
table.table_style_handle = self.style_handle;
|
||||
CmdResult::CommitAndExit(EntityType::Table(table))
|
||||
} else {
|
||||
CmdResult::NeedPoint
|
||||
@@ -144,8 +179,8 @@ impl CadCommand for TableCommand {
|
||||
fn on_mouse_move(&mut self, pt: DVec3) -> Option<WireModel> { let pt = pt.as_vec3();
|
||||
if let Step::Insertion { cols, rows } = self.step {
|
||||
// Preview: outline of the table bounding box.
|
||||
let w = (cols as f32) * COL_WIDTH as f32;
|
||||
let h = (rows as f32) * ROW_HEIGHT as f32;
|
||||
let w = (cols as f32) * (self.column_width * self.preview_scale) as f32;
|
||||
let h = (rows as f32) * (self.row_height * self.preview_scale) as f32;
|
||||
let x = pt.x;
|
||||
let y = pt.y;
|
||||
let z = pt.z;
|
||||
|
||||
@@ -21,12 +21,14 @@ enum Step {
|
||||
|
||||
pub struct TextCommand {
|
||||
step: Step,
|
||||
height: f64,
|
||||
}
|
||||
|
||||
impl TextCommand {
|
||||
pub fn new() -> Self {
|
||||
pub fn with_height(height: f64) -> Self {
|
||||
Self {
|
||||
step: Step::InsertPoint,
|
||||
height,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +50,7 @@ impl CadCommand for TextCommand {
|
||||
pos: pt,
|
||||
handle: None,
|
||||
initial: String::new(),
|
||||
height: 0.25,
|
||||
height: self.height,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,15 +33,25 @@ enum Step {
|
||||
|
||||
pub struct AttdefCommand {
|
||||
step: Step,
|
||||
/// Text height in world units.
|
||||
height: f64,
|
||||
text_style: String,
|
||||
width_factor: f64,
|
||||
oblique_angle: f64,
|
||||
}
|
||||
|
||||
impl AttdefCommand {
|
||||
pub fn new() -> Self {
|
||||
pub fn with_text_defaults(
|
||||
height: f64,
|
||||
text_style: String,
|
||||
width_factor: f64,
|
||||
oblique_angle: f64,
|
||||
) -> Self {
|
||||
Self {
|
||||
step: Step::Tag,
|
||||
height: 0.2,
|
||||
height,
|
||||
text_style,
|
||||
width_factor,
|
||||
oblique_angle,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +140,9 @@ impl CadCommand for AttdefCommand {
|
||||
default_value: default.clone(),
|
||||
insertion_point: Vector3::new(pt.x, pt.y, pt.z),
|
||||
height: self.height,
|
||||
text_style: self.text_style.clone(),
|
||||
width_factor: self.width_factor,
|
||||
oblique_angle: self.oblique_angle,
|
||||
..Default::default()
|
||||
};
|
||||
attdef.common.layer = "0".into();
|
||||
|
||||
@@ -19,6 +19,8 @@ pub struct MlineCommand {
|
||||
scale: f64,
|
||||
waiting_scale: bool,
|
||||
style_name: String,
|
||||
style_handle: Option<acadrust::Handle>,
|
||||
style_element_count: usize,
|
||||
}
|
||||
|
||||
impl MlineCommand {
|
||||
@@ -29,15 +31,23 @@ impl MlineCommand {
|
||||
scale: 1.0,
|
||||
waiting_scale: false,
|
||||
style_name: "Standard".into(),
|
||||
style_handle: None,
|
||||
style_element_count: 2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_style(style_name: impl Into<String>) -> Self {
|
||||
pub fn with_style(
|
||||
style_name: impl Into<String>,
|
||||
style_handle: Option<acadrust::Handle>,
|
||||
style_element_count: usize,
|
||||
) -> Self {
|
||||
Self {
|
||||
points: vec![],
|
||||
scale: 1.0,
|
||||
waiting_scale: false,
|
||||
style_name: style_name.into(),
|
||||
style_handle,
|
||||
style_element_count: style_element_count.max(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +104,14 @@ impl CadCommand for MlineCommand {
|
||||
|
||||
// Close command
|
||||
if (up == "C" || up == "CLOSE") && self.points.len() >= 3 {
|
||||
let entity = build_mline(&self.points, self.scale, true, &self.style_name);
|
||||
let entity = build_mline(
|
||||
&self.points,
|
||||
self.scale,
|
||||
true,
|
||||
&self.style_name,
|
||||
self.style_handle,
|
||||
self.style_element_count,
|
||||
);
|
||||
return Some(CmdResult::CommitAndExit(entity));
|
||||
}
|
||||
|
||||
@@ -126,7 +143,14 @@ impl CadCommand for MlineCommand {
|
||||
if self.points.len() < 2 {
|
||||
return CmdResult::Cancel;
|
||||
}
|
||||
let entity = build_mline(&self.points, self.scale, false, &self.style_name);
|
||||
let entity = build_mline(
|
||||
&self.points,
|
||||
self.scale,
|
||||
false,
|
||||
&self.style_name,
|
||||
self.style_handle,
|
||||
self.style_element_count,
|
||||
);
|
||||
CmdResult::CommitAndExit(entity)
|
||||
}
|
||||
|
||||
@@ -171,18 +195,25 @@ impl CadCommand for MlineCommand {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_mline(pts: &[DVec3], scale: f64, closed: bool, style_name: &str) -> EntityType {
|
||||
let verts: Vec<Vector3> = pts
|
||||
.iter()
|
||||
.map(|p| Vector3::new(p.x, p.y, p.z))
|
||||
.collect();
|
||||
let mut mline = if closed {
|
||||
MLine::closed_from_points(&verts)
|
||||
} else {
|
||||
MLine::from_points(&verts)
|
||||
};
|
||||
fn build_mline(
|
||||
pts: &[DVec3],
|
||||
scale: f64,
|
||||
closed: bool,
|
||||
style_name: &str,
|
||||
style_handle: Option<acadrust::Handle>,
|
||||
style_element_count: usize,
|
||||
) -> EntityType {
|
||||
let mut mline = MLine::new();
|
||||
mline.scale_factor = scale;
|
||||
mline.style_name = style_name.to_string();
|
||||
mline.style_handle = style_handle;
|
||||
mline.style_element_count = style_element_count;
|
||||
for point in pts {
|
||||
mline.add_vertex(Vector3::new(point.x, point.y, point.z));
|
||||
}
|
||||
if closed {
|
||||
mline.close();
|
||||
}
|
||||
EntityType::MLine(mline)
|
||||
}
|
||||
|
||||
|
||||
+50
-1
@@ -639,10 +639,33 @@ pub fn effective_annotation_scale_for(
|
||||
fallback: f32,
|
||||
scale_handle: Option<Handle>,
|
||||
) -> f32 {
|
||||
if !is_annotative(doc, entity) {
|
||||
let context_annotative = is_annotative(doc, entity);
|
||||
let style_annotative = annotation_style_is_annotative(doc, entity);
|
||||
if !context_annotative && !style_annotative {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
if matches!(
|
||||
entity,
|
||||
EntityType::Dimension(_)
|
||||
| EntityType::Leader(_)
|
||||
| EntityType::Tolerance(_)
|
||||
| EntityType::Table(_)
|
||||
) {
|
||||
return fallback;
|
||||
}
|
||||
if style_annotative
|
||||
&& matches!(
|
||||
entity,
|
||||
EntityType::Text(_)
|
||||
| EntityType::MText(_)
|
||||
| EntityType::AttributeEntity(_)
|
||||
| EntityType::AttributeDefinition(_)
|
||||
)
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// Unlike MTEXT / DIMENSION contexts, an MLEADER context carries its
|
||||
// already-scaled text height and overall scale factor. Keep the text
|
||||
// height as stored; make `ml.scale_factor * anno_scale` resolve to the
|
||||
@@ -1392,6 +1415,15 @@ fn mleader_style_annotative(doc: &CadDocument, handle: Option<Handle>) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
fn table_style_annotative(doc: &CadDocument, handle: Option<Handle>) -> bool {
|
||||
let Some(handle) = handle else {
|
||||
return false;
|
||||
};
|
||||
doc.objects.iter().any(|(object_handle, object)| {
|
||||
matches!(object, ObjectType::TableStyle(style) if *object_handle == handle && style.annotative)
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether an object carries a per-object annotation context with at least one
|
||||
/// per-scale representation — its extension dictionary holds an
|
||||
/// `AcDbContextDataManager` whose `ACDB_ANNOTATIONSCALES` collection is
|
||||
@@ -1454,6 +1486,7 @@ pub fn annotation_style_is_annotative(doc: &CadDocument, entity: &EntityType) ->
|
||||
EntityType::MultiLeader(leader) => {
|
||||
mleader_style_annotative(doc, leader.style_handle)
|
||||
}
|
||||
EntityType::Table(table) => table_style_annotative(doc, table.table_style_handle),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -1473,6 +1506,8 @@ pub fn apply_mleader_style(
|
||||
entity.dogleg_length = style.landing_distance;
|
||||
entity.arrowhead_handle = style.arrowhead_handle;
|
||||
entity.arrowhead_size = style.arrowhead_size;
|
||||
entity.context.arrowhead_size = style.arrowhead_size;
|
||||
entity.context.landing_gap = style.landing_gap;
|
||||
entity.text_style_handle = style.text_style_handle;
|
||||
entity.text_color = style.text_color;
|
||||
entity.text_frame = style.text_frame;
|
||||
@@ -1509,6 +1544,20 @@ pub fn apply_mleader_style(
|
||||
entity.context.block_content_scale = entity.block_scale;
|
||||
entity.context.scale_factor = style.scale_factor;
|
||||
entity.enable_annotation_scale = style.is_annotative;
|
||||
for root in &mut entity.context.leader_roots {
|
||||
root.landing_distance = style.landing_distance;
|
||||
root.text_attachment_direction = entity.text_attachment_direction;
|
||||
for line in &mut root.lines {
|
||||
if line.override_flags.is_empty() {
|
||||
line.path_type = entity.path_type;
|
||||
line.line_color = style.line_color;
|
||||
line.line_type_handle = style.line_type_handle;
|
||||
line.line_weight = style.line_weight;
|
||||
line.arrowhead_handle = style.arrowhead_handle;
|
||||
line.arrowhead_size = style.arrowhead_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_mleader_style_to_object(
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
use acadrust::objects::ObjectType;
|
||||
use acadrust::tables::{DimStyle, TextStyle};
|
||||
use acadrust::{CadDocument, EntityType, Handle};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TextCreationDefaults {
|
||||
pub style_name: String,
|
||||
pub height: f64,
|
||||
pub width_factor: f64,
|
||||
pub oblique_angle: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DimensionCreationDefaults {
|
||||
pub style_name: String,
|
||||
pub style_handle: Handle,
|
||||
pub text_style_name: String,
|
||||
pub text_height: f64,
|
||||
pub gap: f64,
|
||||
pub arrow_size: f64,
|
||||
pub scale: f64,
|
||||
pub annotative: bool,
|
||||
}
|
||||
|
||||
fn named_text_style(doc: &CadDocument, name: &str) -> Option<TextStyle> {
|
||||
doc.text_styles
|
||||
.iter()
|
||||
.find(|style| style.name.eq_ignore_ascii_case(name))
|
||||
.or_else(|| {
|
||||
doc.text_styles
|
||||
.iter()
|
||||
.find(|style| style.name.eq_ignore_ascii_case("Standard"))
|
||||
})
|
||||
.cloned()
|
||||
}
|
||||
|
||||
fn named_dim_style(doc: &CadDocument, name: &str) -> Option<DimStyle> {
|
||||
doc.dim_styles
|
||||
.iter()
|
||||
.find(|style| style.name.eq_ignore_ascii_case(name))
|
||||
.or_else(|| {
|
||||
doc.dim_styles
|
||||
.iter()
|
||||
.find(|style| style.name.eq_ignore_ascii_case("Standard"))
|
||||
})
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn current_text_defaults(doc: &CadDocument) -> TextCreationDefaults {
|
||||
let requested = doc.header.current_text_style_name.trim();
|
||||
let style = named_text_style(doc, requested);
|
||||
let variable_height = if doc.header.text_height > 1.0e-9 {
|
||||
doc.header.text_height
|
||||
} else {
|
||||
style
|
||||
.as_ref()
|
||||
.map(|style| style.last_height)
|
||||
.filter(|height| *height > 1.0e-9)
|
||||
.unwrap_or(2.5)
|
||||
};
|
||||
TextCreationDefaults {
|
||||
style_name: style
|
||||
.as_ref()
|
||||
.map(|style| style.name.clone())
|
||||
.filter(|name| !name.trim().is_empty())
|
||||
.unwrap_or_else(|| "Standard".to_string()),
|
||||
height: style
|
||||
.as_ref()
|
||||
.map(|style| style.height)
|
||||
.filter(|height| *height > 1.0e-9)
|
||||
.unwrap_or(variable_height),
|
||||
width_factor: style.as_ref().map_or(1.0, |style| style.width_factor),
|
||||
oblique_angle: style.as_ref().map_or(0.0, |style| style.oblique_angle),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_dimension_defaults(doc: &CadDocument) -> DimensionCreationDefaults {
|
||||
let requested = doc.header.current_dimstyle_name.trim();
|
||||
let style = named_dim_style(doc, requested);
|
||||
DimensionCreationDefaults {
|
||||
style_name: style
|
||||
.as_ref()
|
||||
.map(|style| style.name.clone())
|
||||
.filter(|name| !name.trim().is_empty())
|
||||
.unwrap_or_else(|| "Standard".to_string()),
|
||||
style_handle: style.as_ref().map_or(Handle::NULL, |style| style.handle),
|
||||
text_style_name: style
|
||||
.as_ref()
|
||||
.map(|style| style.dimtxsty.clone())
|
||||
.filter(|name| !name.trim().is_empty())
|
||||
.unwrap_or_else(|| current_text_defaults(doc).style_name),
|
||||
text_height: style.as_ref().map_or(2.5, |style| style.dimtxt),
|
||||
gap: style.as_ref().map_or(0.625, |style| style.dimgap),
|
||||
arrow_size: style.as_ref().map_or(2.5, |style| style.dimasz),
|
||||
scale: style.as_ref().map_or(1.0, |style| {
|
||||
if style.annotative {
|
||||
1.0
|
||||
} else if style.dimscale > 1.0e-9 {
|
||||
style.dimscale
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
}),
|
||||
annotative: style.as_ref().is_some_and(|style| style.annotative),
|
||||
}
|
||||
}
|
||||
|
||||
fn entity_uses_default_style(name: &str) -> bool {
|
||||
name.trim().is_empty() || name.eq_ignore_ascii_case("Standard")
|
||||
}
|
||||
|
||||
fn apply_text_defaults(doc: &CadDocument, entity: &mut EntityType) {
|
||||
let active = current_text_defaults(doc);
|
||||
let style_name = match entity {
|
||||
EntityType::Text(text) => &mut text.style,
|
||||
EntityType::MText(text) => &mut text.style,
|
||||
EntityType::AttributeEntity(attribute) => &mut attribute.text_style,
|
||||
EntityType::AttributeDefinition(attribute) => &mut attribute.text_style,
|
||||
_ => return,
|
||||
};
|
||||
if style_name.trim().is_empty() {
|
||||
style_name.clone_from(&active.style_name);
|
||||
}
|
||||
let resolved = named_text_style(doc, style_name)
|
||||
.unwrap_or_else(|| TextStyle::new(style_name.clone()));
|
||||
match entity {
|
||||
EntityType::Text(text) => {
|
||||
if resolved.height > 1.0e-9 {
|
||||
text.height = resolved.height;
|
||||
}
|
||||
if (text.width_factor - 1.0).abs() <= 1.0e-9 {
|
||||
text.width_factor = resolved.width_factor;
|
||||
}
|
||||
if text.oblique_angle.abs() <= 1.0e-9 {
|
||||
text.oblique_angle = resolved.oblique_angle;
|
||||
}
|
||||
if text.generation_flags == 0 {
|
||||
text.generation_flags = (if resolved.flags.backward { 2 } else { 0 })
|
||||
| (if resolved.flags.upside_down { 4 } else { 0 });
|
||||
}
|
||||
}
|
||||
EntityType::MText(text) => {
|
||||
if resolved.height > 1.0e-9 {
|
||||
text.height = resolved.height;
|
||||
}
|
||||
}
|
||||
EntityType::AttributeEntity(attribute) => {
|
||||
if resolved.height > 1.0e-9 {
|
||||
attribute.height = resolved.height;
|
||||
}
|
||||
if (attribute.width_factor - 1.0).abs() <= 1.0e-9 {
|
||||
attribute.width_factor = resolved.width_factor;
|
||||
}
|
||||
if attribute.oblique_angle.abs() <= 1.0e-9 {
|
||||
attribute.oblique_angle = resolved.oblique_angle;
|
||||
}
|
||||
if attribute.text_generation_flags == 0 {
|
||||
attribute.text_generation_flags =
|
||||
(if resolved.flags.backward { 2 } else { 0 })
|
||||
| (if resolved.flags.upside_down { 4 } else { 0 });
|
||||
}
|
||||
}
|
||||
EntityType::AttributeDefinition(attribute) => {
|
||||
if resolved.height > 1.0e-9 {
|
||||
attribute.height = resolved.height;
|
||||
}
|
||||
if (attribute.width_factor - 1.0).abs() <= 1.0e-9 {
|
||||
attribute.width_factor = resolved.width_factor;
|
||||
}
|
||||
if attribute.oblique_angle.abs() <= 1.0e-9 {
|
||||
attribute.oblique_angle = resolved.oblique_angle;
|
||||
}
|
||||
if attribute.text_generation_flags == 0 {
|
||||
attribute.text_generation_flags =
|
||||
(if resolved.flags.backward { 2 } else { 0 })
|
||||
| (if resolved.flags.upside_down { 4 } else { 0 });
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_dimension_defaults(doc: &CadDocument, entity: &mut EntityType) {
|
||||
let active = current_dimension_defaults(doc);
|
||||
match entity {
|
||||
EntityType::Dimension(dimension) => {
|
||||
if entity_uses_default_style(&dimension.base().style_name) {
|
||||
dimension.base_mut().style_name.clone_from(&active.style_name);
|
||||
}
|
||||
}
|
||||
EntityType::Leader(leader) => {
|
||||
if entity_uses_default_style(&leader.dimension_style) {
|
||||
leader.dimension_style.clone_from(&active.style_name);
|
||||
leader.text_height = active.text_height;
|
||||
leader.dimension_gap = active.gap;
|
||||
leader.arrow_size = active.arrow_size;
|
||||
}
|
||||
}
|
||||
EntityType::Tolerance(tolerance) => {
|
||||
if entity_uses_default_style(&tolerance.dimension_style_name) {
|
||||
tolerance.dimension_style_name.clone_from(&active.style_name);
|
||||
tolerance.dimension_style_handle = (!active.style_handle.is_null())
|
||||
.then_some(active.style_handle);
|
||||
tolerance.text_height = active.text_height;
|
||||
tolerance.dimension_gap = active.gap;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_object_defaults(doc: &CadDocument, entity: &mut EntityType) {
|
||||
match entity {
|
||||
EntityType::MultiLeader(leader) if leader.style_handle.is_none() => {
|
||||
let name = doc.header.current_mleader_style_name.trim();
|
||||
if let Some(style) = doc.objects.iter().find_map(|(handle, object)| match object {
|
||||
ObjectType::MultiLeaderStyle(style) if style.name.eq_ignore_ascii_case(name) => {
|
||||
let mut style = style.clone();
|
||||
style.handle = *handle;
|
||||
Some(style)
|
||||
}
|
||||
_ => None,
|
||||
}) {
|
||||
crate::scene::annotative::apply_mleader_style(leader, &style);
|
||||
}
|
||||
}
|
||||
EntityType::Table(table) if table.table_style_handle.is_none() => {
|
||||
let name = doc.header.current_table_style_name.trim();
|
||||
table.table_style_handle = doc.objects.iter().find_map(|(handle, object)| match object {
|
||||
ObjectType::TableStyle(style) if style.name.eq_ignore_ascii_case(name) => {
|
||||
Some(*handle)
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
}
|
||||
EntityType::MLine(mline) if mline.style_handle.is_none() => {
|
||||
let name = doc.header.multiline_style.trim();
|
||||
if let Some((handle, style_name)) =
|
||||
doc.objects.iter().find_map(|(handle, object)| match object {
|
||||
ObjectType::MLineStyle(style) if style.name.eq_ignore_ascii_case(name) => {
|
||||
Some((*handle, style.name.clone()))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
mline.style_handle = Some(handle);
|
||||
mline.style_name = style_name;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_current_creation_styles(doc: &CadDocument, entity: &mut EntityType) {
|
||||
apply_text_defaults(doc, entity);
|
||||
apply_dimension_defaults(doc, entity);
|
||||
apply_object_defaults(doc, entity);
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
pub mod annotative;
|
||||
pub mod cache;
|
||||
pub mod convert;
|
||||
pub mod creation_style;
|
||||
pub mod model;
|
||||
pub mod pick;
|
||||
pub mod pipeline;
|
||||
@@ -3800,6 +3801,28 @@ impl Scene {
|
||||
self.scale_handle_ensuring("1:1")
|
||||
}
|
||||
|
||||
pub(crate) fn creation_annotation_multiplier(&self) -> f64 {
|
||||
if self.current_layout == "Model" {
|
||||
return self.annotation_scale.max(1.0e-9) as f64;
|
||||
}
|
||||
let Some(handle) = self.active_viewport else {
|
||||
return 1.0;
|
||||
};
|
||||
let Some(EntityType::Viewport(viewport)) = self.document.get_entity(handle) else {
|
||||
return 1.0;
|
||||
};
|
||||
let paper_to_model = vp_effective_scale(
|
||||
viewport.custom_scale,
|
||||
viewport.view_height,
|
||||
viewport.height,
|
||||
);
|
||||
if paper_to_model.is_finite() && paper_to_model > 1.0e-9 {
|
||||
1.0 / paper_to_model
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_annotation_scale_named(&mut self, name: &str) -> Option<Handle> {
|
||||
let handle = self.scale_handle_ensuring(name)?;
|
||||
let ObjectType::Scale(scale) = self.document.objects.get(&handle)? else {
|
||||
|
||||
Reference in new issue
Block a user