using OpenNest.Geometry; namespace OpenNest.Shapes { public enum ShapeDimensionKind { /// A dimension line outside the shape, past its bounds on the side. Linear, /// A dimension line drawn directly between the two points, such as across a hole. Inline, /// A leader from out along . Leader, } /// /// Where the Shape Library draws one parameter's dimension on the shape's preview, in the /// shape's own coordinates (those of the entities /// builds). Annotation only: it never affects the drawing. /// 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 ?? ""; } /// The name of the shape property the dimension shows and edits. public string Property { get; } public ShapeDimensionKind Kind { get; } public Vector Start { get; } /// The second measured point; equal to for a leader. public Vector End { get; } /// Unit vector: the side a linear dimension sits on, or a leader's direction. public Vector Side { get; } /// Text before the value, such as "Ø" or "R". public string Prefix { get; } /// /// 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. /// public string CountProperty { get; private init; } /// The plural noun after the count, such as "holes". public string CountNoun { get; private init; } /// /// The center of the hole a diameter leader calls out; null for other dimensions. /// The leader's line crosses the hole through it, whichever way the label is dragged. /// public Vector? HoleCenter { get; private init; } /// The radius of the hole at . public double HoleRadius { get; private init; } /// /// The center of a reference circle (such as a flange's bolt circle) that the preview /// draws dotted; null when there is none. /// public Vector? CircleCenter { get; private init; } /// The radius of the reference circle at . public double CircleRadius { get; private init; } /// True when the preview draws a dotted reference circle for this dimension. public bool DrawsCircle => CircleCenter != null; /// This dimension with "x {count} {noun}" after its value. public ShapeDimension WithCount(string countProperty, string noun) => new(Property, Kind, Start, End, Side, Prefix) { CountProperty = countProperty, CountNoun = noun, HoleCenter = HoleCenter, HoleRadius = HoleRadius, CircleCenter = CircleCenter, CircleRadius = CircleRadius, }; /// /// Measures from to across /// , which must be one of the four axis directions. /// 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); } /// /// A diameter leader on the hole at : it starts on the hole's /// edge facing , and its line runs across the hole through the center. /// public static ShapeDimension HoleLeader(string property, Vector center, double radius, Vector direction, string prefix = "") { var length = System.Math.Sqrt(direction.X * direction.X + direction.Y * direction.Y); var unit = new Vector(direction.X / length, direction.Y / length); var edge = new Vector(center.X + unit.X * radius, center.Y + unit.Y * radius); return new(property, ShapeDimensionKind.Leader, edge, edge, unit, prefix) { HoleCenter = center, HoleRadius = radius, }; } /// /// A diameter leader on a dotted reference circle (such as a flange's bolt circle) at /// : it starts on the circle facing /// and runs out from there, its arrow pointing in onto the circle; no line crosses it. /// public static ShapeDimension CircleLeader(string property, Vector center, double radius, Vector direction, string prefix = "") { var length = System.Math.Sqrt(direction.X * direction.X + direction.Y * direction.Y); var unit = new Vector(direction.X / length, direction.Y / length); var edge = new Vector(center.X + unit.X * radius, center.Y + unit.Y * radius); return new(property, ShapeDimensionKind.Leader, edge, edge, unit, prefix) { CircleCenter = center, CircleRadius = radius, }; } /// The distance the dimension shows between its points (zero for a leader). 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); } }