forked from 1b-agent/opencadstudio-upstream
fix(mleader): straight leaders, real landing + connection-anchored text (#347)
Render MultiLeader labels from the stored context fields instead of re-deriving them: - Draw each leader line with the line's own path type (code 170) rather than the MultiLeader's overall/style type. A spline-style leader can carry straight lines; splining a straight two-point run through Catmull-Rom bowed it, so the leader looked wavy with a dirty elbow. - Drop the stray landing segment that ran from the dogleg end up to the text's top-left insertion, leaving just the horizontal dogleg. - Anchor the horizontal-leader text so its bottom line sits at the connection point (the box then spans connection.y → text_location.y, matching the writer's content_base_point + landing_gap geometry). Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
208bb099d5
commit
b61bc0fdc0
1 file changed
+30
-14
+30
-14
@@ -205,8 +205,10 @@ fn to_truck(ml: &MultiLeader, document: &acadrust::CadDocument) -> Option<TruckE
|
||||
snap_pts.push(node(c));
|
||||
}
|
||||
|
||||
if ml.path_type == MultiLeaderPathType::Spline && ctrl.len() >= 2 {
|
||||
// Catmull-Rom spline through the bend points.
|
||||
if line.path_type == MultiLeaderPathType::Spline && ctrl.len() >= 2 {
|
||||
// Catmull-Rom spline through the bend points. Use the leader
|
||||
// line's own path type — a spline-style MultiLeader can carry
|
||||
// straight lines, and splining a straight run bows it.
|
||||
let pts = catmull_rom_pts(&ctrl, 8);
|
||||
for &pt in &pts {
|
||||
points.push(pt);
|
||||
@@ -1212,7 +1214,11 @@ impl MultiLeaderTess for MultiLeader {
|
||||
snap_pts.push((Vec3::from(c).as_dvec3(), SnapHint::Node));
|
||||
}
|
||||
|
||||
if ml.path_type == MultiLeaderPathType::Spline && ctrl.len() >= 2 {
|
||||
// Use the leader LINE's own path type (its stored 170 code),
|
||||
// not the MultiLeader's overall/style default: a spline-style
|
||||
// leader can carry straight lines, and drawing those through a
|
||||
// Catmull-Rom bows an otherwise-straight two-point segment.
|
||||
if line.path_type == MultiLeaderPathType::Spline && ctrl.len() >= 2 {
|
||||
let ctrl_f64: Vec<[f64; 3]> = ctrl
|
||||
.iter()
|
||||
.map(|c| [c[0] as f64, c[1] as f64, c[2] as f64])
|
||||
@@ -1259,7 +1265,12 @@ impl MultiLeaderTess for MultiLeader {
|
||||
}
|
||||
|
||||
if ml.enable_landing && ml.enable_dogleg && ml.dogleg_length > 0.0 {
|
||||
// Horizontal landing toward the text's side (mirrors live).
|
||||
// Horizontal landing (dogleg) from the leader elbow (connection
|
||||
// point) toward the text side. The stored geometry places the
|
||||
// text so its near-bottom edge sits one landing_gap past this
|
||||
// dogleg end, so the dogleg stops here — drawing on to
|
||||
// text_location (the block's top-left insertion) would streak a
|
||||
// stray line up the side of the text.
|
||||
let d = ml.dogleg_length * effective_scale as f64;
|
||||
let landing_end = [
|
||||
(cp.x + text_sign_w * d) as f32,
|
||||
@@ -1269,15 +1280,6 @@ impl MultiLeaderTess for MultiLeader {
|
||||
points.push(nan);
|
||||
points.push(cp_f);
|
||||
points.push(landing_end);
|
||||
// Continue the landing to the text's near edge so it stays
|
||||
// attached as the text moves.
|
||||
if ml.content_type == LeaderContentType::MText && !ml.context.text_string.is_empty()
|
||||
{
|
||||
let tx = (ml.context.text_location.x) as f32;
|
||||
let ty = (ml.context.text_location.y) as f32;
|
||||
points.push(landing_end);
|
||||
points.push([tx, ty, cp_f[2]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1399,7 +1401,21 @@ impl MultiLeaderTess for MultiLeader {
|
||||
// sit at large absolute coordinates and casting first then subtracting
|
||||
// throws away the precision needed for the rotated sub-glyph offsets.
|
||||
let local_ins_x = (ins.x) as f32;
|
||||
let local_ins_y = (ins.y) as f32;
|
||||
// Horizontal leaders attach at the connection point: the dogleg runs
|
||||
// horizontally at connection_point.y, and the text's attachment line
|
||||
// (bottom/middle/top per text_left_attachment) sits there. Anchor the
|
||||
// insertion Y to that connection instead of the stored text_location.y
|
||||
// so the text meets the landing exactly — the two can disagree by a
|
||||
// few percent because our MText line height need not match the writer's.
|
||||
let local_ins_y = match ml.text_attachment_direction {
|
||||
TextAttachmentDirectionType::Horizontal => ml
|
||||
.context
|
||||
.leader_roots
|
||||
.first()
|
||||
.map(|r| r.connection_point.y as f32)
|
||||
.unwrap_or(ins.y as f32),
|
||||
TextAttachmentDirectionType::Vertical => ins.y as f32,
|
||||
};
|
||||
let z = (ins.z) as f32;
|
||||
|
||||
// Rotation: prefer text_direction (transforms survive rotations /
|
||||
|
||||
Reference in new issue
Block a user