forked from 1b-agent/opencadstudio-upstream
Match Vertical geometric constraint behavior
1) VCONSTRAINT (and the new GCVERTICAL name) uses the axis constraint flow: "Select an object or [2Points] <2Points>:", 2Points mode with the reference's re-prompts and messages, and the same object types as Horizontal — line, polyline segment, text, MText, ellipse axis. 2) Object mode turns the object about its first vertex; a two-point relation across two objects slides the second object rigidly onto the axis. 3) Re-applying an axis constraint reports that the constraint already exists; Vertical follows the UCS Y direction. 4) The constraint bar draws Vertical as the reference's axis mark, with the point marker for a two-point relation. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
2b38f798c0
commit
26e458d6f7
6 files changed
+271
-75
No files matched your search
+56
-1
@@ -34,11 +34,16 @@ fn is_compact_coincident_glyph(label: &str) -> bool {
|
||||
matches!(label, "≡" | "∈")
|
||||
}
|
||||
|
||||
/// Vertical's two axis-mark labels (`parametric_constraints::vertical_glyph_label`).
|
||||
fn is_vertical_glyph(label: &str) -> bool {
|
||||
label == "│" || label == crate::scene::parametric_constraints::VERTICAL_POINTS_GLYPH
|
||||
}
|
||||
|
||||
fn constraint_glyph_size(label: &str) -> Size {
|
||||
if is_compact_coincident_glyph(label) {
|
||||
return Size::new(COINCIDENT_GLYPH_SIZE, COINCIDENT_GLYPH_SIZE);
|
||||
}
|
||||
if label == "G²" {
|
||||
if label == "G²" || is_vertical_glyph(label) {
|
||||
let side = CONSTRAINT_GLYPH_SIZE + CONSTRAINT_GLYPH_PAD_Y * 2.0;
|
||||
return Size::new(side, side);
|
||||
}
|
||||
@@ -94,6 +99,49 @@ fn draw_concentric_constraint_glyph(
|
||||
frame.stroke(&canvas::Path::circle(center, 2.15), stroke);
|
||||
}
|
||||
|
||||
/// The reference bar's Vertical mark: a red datum line hatched on its left,
|
||||
/// the constrained direction beside it, plus the orange point marker for a
|
||||
/// two-point relation.
|
||||
fn draw_vertical_constraint_glyph(
|
||||
frame: &mut canvas::Frame,
|
||||
center: Point,
|
||||
text: Color,
|
||||
point_marker: bool,
|
||||
) {
|
||||
let datum = Color::from_rgb8(214, 76, 76);
|
||||
let datum_x = center.x - 2.5;
|
||||
let stroke = canvas::Stroke::default().with_color(datum).with_width(1.5);
|
||||
frame.stroke(
|
||||
&canvas::Path::line(
|
||||
Point::new(datum_x, center.y - 6.5),
|
||||
Point::new(datum_x, center.y + 6.5),
|
||||
),
|
||||
stroke.clone(),
|
||||
);
|
||||
for step in 0..3 {
|
||||
let y = center.y - 4.5 + step as f32 * 4.0;
|
||||
frame.stroke(
|
||||
&canvas::Path::line(Point::new(datum_x, y), Point::new(datum_x - 4.0, y + 3.5)),
|
||||
stroke.clone(),
|
||||
);
|
||||
}
|
||||
frame.stroke(
|
||||
&canvas::Path::line(
|
||||
Point::new(center.x + 2.5, center.y - 6.0),
|
||||
Point::new(center.x + 2.5, center.y + 6.0),
|
||||
),
|
||||
canvas::Stroke::default().with_color(text).with_width(1.4),
|
||||
);
|
||||
if point_marker {
|
||||
frame.stroke(
|
||||
&canvas::Path::rectangle(Point::new(center.x + 4.5, center.y - 2.3), Size::new(4.6, 4.6)),
|
||||
canvas::Stroke::default()
|
||||
.with_color(Color::from_rgb8(224, 130, 62))
|
||||
.with_width(1.2),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn constraint_glyph_box(
|
||||
anchor: Point,
|
||||
outward: [f32; 2],
|
||||
@@ -2020,6 +2068,13 @@ impl canvas::Program<Message> for SelectionCanvas {
|
||||
draw_smooth_constraint_glyph(&mut frame, glyph_center, fg);
|
||||
} else if label == "◎" {
|
||||
draw_concentric_constraint_glyph(&mut frame, glyph_center, fg);
|
||||
} else if is_vertical_glyph(label) {
|
||||
draw_vertical_constraint_glyph(
|
||||
&mut frame,
|
||||
glyph_center,
|
||||
fg,
|
||||
label == crate::scene::parametric_constraints::VERTICAL_POINTS_GLYPH,
|
||||
);
|
||||
} else {
|
||||
frame.fill_text(canvas::Text {
|
||||
content: label.clone(),
|
||||
|
||||
Reference in new issue
Block a user