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);
}
}