fix(geometry): add Entity.Clone() and stop NormalizeEntities from mutating originals
ShapeProfile.NormalizeEntities called Shape.Reverse() which flipped arc directions on the original entity objects shared with the CAD view. Switching to the Program tab and back would leave arcs reversed. Clone entities before normalizing so the originals stay untouched. Adds abstract Entity.Clone() with implementations on Line, Arc, Circle, Polygon, and Shape (deep-clones children). Also adds CloneAll() extension and replaces manual duplication in PartGeometry.CopyEntitiesAtLocation and ProgramEditorControl.CloneEntity. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -267,6 +267,13 @@ namespace OpenNest.Geometry
|
|||||||
get { return Diameter * System.Math.PI * SweepAngle() / Angle.TwoPI; }
|
get { return Diameter * System.Math.PI * SweepAngle() / Angle.TwoPI; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Entity Clone()
|
||||||
|
{
|
||||||
|
var copy = new Arc(center, radius, startAngle, endAngle, reversed);
|
||||||
|
CopyBaseTo(copy);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reverses the rotation direction.
|
/// Reverses the rotation direction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -165,6 +165,13 @@ namespace OpenNest.Geometry
|
|||||||
get { return Circumference(); }
|
get { return Circumference(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Entity Clone()
|
||||||
|
{
|
||||||
|
var copy = new Circle(center, radius) { Rotation = Rotation };
|
||||||
|
CopyBaseTo(copy);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reverses the rotation direction.
|
/// Reverses the rotation direction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -251,6 +251,23 @@ namespace OpenNest.Geometry
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract bool Intersects(Shape shape, out List<Vector> pts);
|
public abstract bool Intersects(Shape shape, out List<Vector> pts);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a deep copy of the entity with a new Id.
|
||||||
|
/// </summary>
|
||||||
|
public abstract Entity Clone();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies common Entity properties from this instance to the target.
|
||||||
|
/// </summary>
|
||||||
|
protected void CopyBaseTo(Entity target)
|
||||||
|
{
|
||||||
|
target.Color = Color;
|
||||||
|
target.Layer = Layer;
|
||||||
|
target.LineTypeName = LineTypeName;
|
||||||
|
target.IsVisible = IsVisible;
|
||||||
|
target.Tag = Tag;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Type of entity.
|
/// Type of entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -259,6 +276,14 @@ namespace OpenNest.Geometry
|
|||||||
|
|
||||||
public static class EntityExtensions
|
public static class EntityExtensions
|
||||||
{
|
{
|
||||||
|
public static List<Entity> CloneAll(this IEnumerable<Entity> entities)
|
||||||
|
{
|
||||||
|
var result = new List<Entity>();
|
||||||
|
foreach (var e in entities)
|
||||||
|
result.Add(e.Clone());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<Vector> CollectPoints(this IEnumerable<Entity> entities)
|
public static List<Vector> CollectPoints(this IEnumerable<Entity> entities)
|
||||||
{
|
{
|
||||||
var points = new List<Vector>();
|
var points = new List<Vector>();
|
||||||
|
|||||||
@@ -257,6 +257,13 @@ namespace OpenNest.Geometry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Entity Clone()
|
||||||
|
{
|
||||||
|
var copy = new Line(pt1, pt2);
|
||||||
|
CopyBaseTo(copy);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reversed the line.
|
/// Reversed the line.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -168,6 +168,13 @@ namespace OpenNest.Geometry
|
|||||||
get { return Perimeter(); }
|
get { return Perimeter(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Entity Clone()
|
||||||
|
{
|
||||||
|
var copy = new Polygon { Vertices = new List<Vector>(Vertices) };
|
||||||
|
CopyBaseTo(copy);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reverses the rotation direction of the polygon.
|
/// Reverses the rotation direction of the polygon.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -349,6 +349,15 @@ namespace OpenNest.Geometry
|
|||||||
return polygon;
|
return polygon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Entity Clone()
|
||||||
|
{
|
||||||
|
var copy = new Shape();
|
||||||
|
foreach (var e in Entities)
|
||||||
|
copy.Entities.Add(e.Clone());
|
||||||
|
CopyBaseTo(copy);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reverses the rotation direction of the shape.
|
/// Reverses the rotation direction of the shape.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ namespace OpenNest.Geometry
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static List<Entity> NormalizeEntities(IEnumerable<Entity> entities)
|
public static List<Entity> NormalizeEntities(IEnumerable<Entity> entities)
|
||||||
{
|
{
|
||||||
var profile = new ShapeProfile(entities.ToList());
|
var cloned = entities.CloneAll();
|
||||||
|
var profile = new ShapeProfile(cloned);
|
||||||
return profile.ToNormalizedEntities();
|
return profile.ToNormalizedEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,20 +126,10 @@ namespace OpenNest
|
|||||||
{
|
{
|
||||||
var result = new List<Entity>(source.Count);
|
var result = new List<Entity>(source.Count);
|
||||||
|
|
||||||
for (var i = 0; i < source.Count; i++)
|
foreach (var entity in source)
|
||||||
{
|
{
|
||||||
var entity = source[i];
|
var copy = entity.Clone();
|
||||||
Entity copy;
|
copy.Offset(location);
|
||||||
|
|
||||||
if (entity is Line line)
|
|
||||||
copy = new Line(line.StartPoint + location, line.EndPoint + location);
|
|
||||||
else if (entity is Arc arc)
|
|
||||||
copy = new Arc(arc.Center + location, arc.Radius, arc.StartAngle, arc.EndAngle, arc.IsReversed);
|
|
||||||
else if (entity is Circle circle)
|
|
||||||
copy = new Circle(circle.Center + location, circle.Radius);
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
result.Add(copy);
|
result.Add(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -209,14 +209,7 @@ namespace OpenNest.Controls
|
|||||||
|
|
||||||
private static Entity CloneEntity(Entity entity, Color color)
|
private static Entity CloneEntity(Entity entity, Color color)
|
||||||
{
|
{
|
||||||
Entity clone = entity switch
|
var clone = entity.Clone();
|
||||||
{
|
|
||||||
Line line => new Line(line.StartPoint, line.EndPoint) { Layer = line.Layer, IsVisible = line.IsVisible },
|
|
||||||
Arc arc => new Arc(arc.Center, arc.Radius, arc.StartAngle, arc.EndAngle, arc.IsReversed) { Layer = arc.Layer, IsVisible = arc.IsVisible },
|
|
||||||
Circle circle => new Circle(circle.Center, circle.Radius) { Layer = circle.Layer, IsVisible = circle.IsVisible },
|
|
||||||
_ => null,
|
|
||||||
};
|
|
||||||
if (clone != null)
|
|
||||||
clone.Color = color;
|
clone.Color = color;
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user