Files
OpenNest/OpenNest.Core/Shapes/ShapeDimension.cs
T
ajandClaude Opus 5.5 6be8a7b41c feat(ui): edit Shape Library parameters as dimensions on the drawing
The Shape Library no longer has a side panel of inputs. Each length is a
dimension line or leader on the preview; click its label to type a new
value (Enter applies, Esc cancels, Tab moves to the next dimension), as
Edit Clamps does on the plate. Invalid values keep the editor open in
red and the last good shape on screen. Settings with no place on the
drawing (sides, pipe size, clearance, blind) are clickable notes along
the bottom. The flange hole leader carries the count beside the size,
such as "Ø7/8" x 8 holes".

Shapes declare their dimensions through ShapeDefinition.GetDimensions;
lengths show as fractions when exact to 1/64 (Fraction.Format). Edit
Clamps' inline text box moves to a shared DimensionBox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 19:25:43 -05:00

97 lines
4.1 KiB
C#

using OpenNest.Geometry;
namespace OpenNest.Shapes
{
public enum ShapeDimensionKind
{
/// <summary>A dimension line outside the shape, past its bounds on the <see cref="ShapeDimension.Side"/> side.</summary>
Linear,
/// <summary>A dimension line drawn directly between the two points, such as across a hole.</summary>
Inline,
/// <summary>A leader from <see cref="ShapeDimension.Start"/> out along <see cref="ShapeDimension.Side"/>.</summary>
Leader,
}
/// <summary>
/// Where the Shape Library draws one parameter's dimension on the shape's preview, in the
/// shape's own coordinates (those of the entities <see cref="ShapeDefinition.GetDrawing"/>
/// builds). Annotation only: it never affects the drawing.
/// </summary>
public sealed class ShapeDimension
{
private ShapeDimension(string property, ShapeDimensionKind kind, Vector start, Vector end, Vector side, string prefix)
{
Property = property;
Kind = kind;
Start = start;
End = end;
Side = side;
Prefix = prefix ?? "";
}
/// <summary>The name of the shape property the dimension shows and edits.</summary>
public string Property { get; }
public ShapeDimensionKind Kind { get; }
public Vector Start { get; }
/// <summary>The second measured point; equal to <see cref="Start"/> for a leader.</summary>
public Vector End { get; }
/// <summary>Unit vector: the side a linear dimension sits on, or a leader's direction.</summary>
public Vector Side { get; }
/// <summary>Text before the value, such as "Ø" or "R".</summary>
public string Prefix { get; }
/// <summary>
/// An integer property shown after the value as "x {count} {noun}", such as a
/// flange's hole count beside its hole diameter; null when there is none.
/// </summary>
public string CountProperty { get; private init; }
/// <summary>The plural noun after the count, such as "holes".</summary>
public string CountNoun { get; private init; }
/// <summary>This dimension with "x {count} {noun}" after its value.</summary>
public ShapeDimension WithCount(string countProperty, string noun) =>
new(Property, Kind, Start, End, Side, Prefix) { CountProperty = countProperty, CountNoun = noun };
/// <summary>
/// Measures from <paramref name="start"/> to <paramref name="end"/> across
/// <paramref name="side"/>, which must be one of the four axis directions.
/// </summary>
public static ShapeDimension Linear(string property, Vector start, Vector end, Vector side, string prefix = "") =>
new(property, ShapeDimensionKind.Linear, start, end, side, prefix);
public static ShapeDimension Inline(string property, Vector start, Vector end, string prefix = "") =>
new(property, ShapeDimensionKind.Inline, start, end, new Vector(0, 1), prefix);
public static ShapeDimension Leader(string property, Vector point, Vector direction, string prefix = "")
{
var length = System.Math.Sqrt(direction.X * direction.X + direction.Y * direction.Y);
return new(property, ShapeDimensionKind.Leader, point, point,
new Vector(direction.X / length, direction.Y / length), prefix);
}
/// <summary>The distance the dimension shows between its points (zero for a leader).</summary>
public double Measured =>
Kind switch
{
ShapeDimensionKind.Linear => System.Math.Abs(Side.X) > System.Math.Abs(Side.Y)
? System.Math.Abs(End.Y - Start.Y)
: System.Math.Abs(End.X - Start.X),
ShapeDimensionKind.Inline => Start.DistanceTo(End),
_ => 0,
};
internal static readonly Vector Up = new(0, 1);
internal static readonly Vector Down = new(0, -1);
internal static readonly Vector Left = new(-1, 0);
internal static readonly Vector Right = new(1, 0);
}
}