/
docNemo
/
clothes-graph
Обзор
Документация
Войти
/
docNemo
/
clothes-graph
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/ClothesGraph.Model/Drafting/PointNodes.cs
134 строки
5 KB
docNemo
Фундамент продукта: параметрическое построение выкроек, печать, установщик
08 авг 2026, 22:17
08 авг 2026, 22:17
cd47cce
Код
Авторство
О чём код?
using System.Collections.Generic; using System.Linq; using ClothesGraph.Geometry; using ClothesGraph.Model.Formulas; using ClothesGraph.Model.Measurements; namespace ClothesGraph.Model.Drafting; /// <summary> /// Точка, заданная координатами. Обычно начало координат чертежа. /// </summary> /// <remarks> /// Свойства открыты для изменения, но менять их следует через /// <see cref="DraftGraph.Update"/>: он проверяет появление цикла и помечает /// зависящие построения требующими пересчёта. /// </remarks> public sealed class FreePoint(NodeId id, string name, Formula x, Formula y) : PointNode(id, name) { public Formula X { get; set; } = x; public Formula Y { get; set; } = y; public override IEnumerable<NodeId> Dependencies => X.Nodes.Concat(Y.Nodes); public override IEnumerable<MeasurementId> MeasurementDependencies => X.Measurements.Concat(Y.Measurements); public override Point2 Evaluate(INodeEvaluationContext context) => new(context.ToLength(X.Evaluate(context)), context.ToLength(Y.Evaluate(context))); public override DraftNode Clone() => new FreePoint(Id, Name, X, Y); } /// <summary> /// Точка на заданном расстоянии и под заданным углом от другой точки. /// </summary> /// <remarks> /// Основной способ построения в методиках конструирования: «от точки А вправо /// отложить Ог/4 + прибавка». /// </remarks> public sealed class OffsetPoint( NodeId id, string name, NodeId origin, Formula distance, Formula angleDegrees) : PointNode(id, name) { public NodeId Origin { get; set; } = origin; public Formula Distance { get; set; } = distance; public Formula AngleDegrees { get; set; } = angleDegrees; public override IEnumerable<NodeId> Dependencies => new[] { Origin }.Concat(Distance.Nodes).Concat(AngleDegrees.Nodes); public override IEnumerable<MeasurementId> MeasurementDependencies => Distance.Measurements.Concat(AngleDegrees.Measurements); public override Point2 Evaluate(INodeEvaluationContext context) { var origin = context.GetPoint(Origin); var distance = context.ToLength(Distance.Evaluate(context)); var angle = AngleDegrees.Evaluate(context); return origin + Offset2.FromPolar(distance, angle); } public override DraftNode Clone() => new OffsetPoint(Id, Name, Origin, Distance, AngleDegrees); } /// <summary> /// Точка на линии: по доле длины либо по расстоянию от начала. /// </summary> public sealed class PointOnCurve( NodeId id, string name, NodeId curve, Formula position, PointOnCurveMode mode) : PointNode(id, name) { public NodeId Curve { get; set; } = curve; public Formula Position { get; set; } = position; public PointOnCurveMode Mode { get; set; } = mode; public override IEnumerable<NodeId> Dependencies => new[] { Curve }.Concat(Position.Nodes); public override IEnumerable<MeasurementId> MeasurementDependencies => Position.Measurements; public override Point2 Evaluate(INodeEvaluationContext context) { var curve = context.GetCurve(Curve); var position = Position.Evaluate(context); return Mode == PointOnCurveMode.Parameter ? curve.PointAt(position) : curve.PointAtDistance(context.ToLength(position)); } public override DraftNode Clone() => new PointOnCurve(Id, Name, Curve, Position, Mode); } public enum PointOnCurveMode { /// <summary>Доля от начала линии в пределах от нуля до единицы.</summary> Parameter, /// <summary>Расстояние от начала линии вдоль неё.</summary> Distance } /// <summary> /// Точка пересечения двух линий. /// </summary> /// <remarks> /// Построение разрешимо не всегда: после смены мерок линии могут разойтись. /// В этом случае узел сообщает о неразрешимости, а не подставляет произвольную /// точку — иначе ошибка расползлась бы по всему чертежу. /// </remarks> public sealed class IntersectionPoint(NodeId id, string name, NodeId first, NodeId second) : PointNode(id, name) { public NodeId First { get; set; } = first; public NodeId Second { get; set; } = second; public override IEnumerable<NodeId> Dependencies => [First, Second]; public override IEnumerable<MeasurementId> MeasurementDependencies => []; public override Point2 Evaluate(INodeEvaluationContext context) { var first = context.GetCurve(First); var second = context.GetCurve(Second); return CurveIntersection.Solve(first, second) ?? throw new NodeUnresolvableException("Линии не пересекаются"); } public override DraftNode Clone() => new IntersectionPoint(Id, Name, First, Second); }