Improving path editor

This commit is contained in:
MatterHackers 2023-11-05 17:26:43 -08:00
parent dfb5700bf8
commit bb8d8b3859
6 changed files with 268 additions and 75 deletions

View file

@ -75,16 +75,11 @@ namespace MatterHackers.MatterControl.DesignTools
private void VertexBufferChanged()
{
object3D.Invalidate(InvalidateType.Path);
object3D.Invalidate(new InvalidateArgs(null, InvalidateType.Path));
}
[AttributeUsage(AttributeTargets.Property)]
public class TopAndBottomMoveXOnlyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class XMustBeGreaterThan0Attribute : Attribute
public class ShowAxisAttribute : Attribute
{
}
}

View file

@ -34,15 +34,23 @@ using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.ImageProcessing;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.SlicerConfiguration;
using MatterHackers.VectorMath;
using System;
using static MatterHackers.MatterControl.PartPreviewWindow.GCode2DWidget;
namespace MatterHackers.MatterControl.DesignTools
{
public class PathEditorWidget : GuiWidget
{
public enum ETransformState
{
Edit,
Move,
Scale
};
private Vector2 lastMousePosition = new Vector2(0, 0);
private ETransformState mouseDownTransformOverride;
private Vector2 mouseDownPosition = new Vector2(0, 0);
private Action<Vector2, double> scaleChanged;
private ThemeConfig theme;
@ -56,7 +64,7 @@ namespace MatterHackers.MatterControl.DesignTools
UndoBuffer undoBuffer,
ThemeConfig theme,
Action vertexChanged,
Vector2 unscaledRenderOffset = default(Vector2),
Vector2 unscaledRenderOffset = default,
double layerScale = 1,
Action<Vector2, double> scaleChanged = null)
{
@ -85,13 +93,76 @@ namespace MatterHackers.MatterControl.DesignTools
var toolBar = new FlowLayoutWidget()
{
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Bottom
Margin = 5,
BackgroundColor= theme.TextColor.WithAlpha(20),
};
toolBar.VAnchor |= VAnchor.Bottom;
this.AddChild(toolBar);
var menuTheme = ApplicationController.Instance.MenuTheme;
var homeButton = new ThemedTextIconButton("Home".Localize(), StaticData.Instance.LoadIcon("fa-home_16.png", 16, 16).GrayToColor(menuTheme.TextColor), theme)
AddHomeButton(theme, toolBar);
toolBar.AddChild(new HorizontalSpacer());
AddPositionControls(theme, toolBar);
}
public static readonly int VectorXYEditWidth = (int)(60 * GuiWidget.DeviceScale + .5);
private void AddPositionControls(ThemeConfig theme, FlowLayoutWidget toolBar)
{
var tabIndex = 0;
var xEditWidget = new ThemedNumberEdit(0, theme, singleCharLabel: 'X', allowNegatives: true, allowDecimals: true, pixelWidth: VectorXYEditWidth, tabIndex: tabIndex)
{
TabIndex = tabIndex++,
SelectAllOnFocus = true,
Margin = theme.ButtonSpacing,
VAnchor = VAnchor.Center,
};
xEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
{
if (controlPointBeingDragged > -1)
{
var vertexData = vertexStorage[controlPointBeingDragged];
if (vertexData.Hint == CommandHint.C4Point)
{
// the prev point
if (controlPointBeingDragged > 0)
{
controlPointBeingDragged--;
vertexData = new VertexData(vertexData.Command, new Vector2(vertexData.Position.X, xEditWidget.ActuallNumberEdit.Value), vertexData.Hint);
controlPointBeingDragged++;
}
}
else
{
}
}
};
xEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
toolBar.AddChild(xEditWidget);
var yEditWidget = new ThemedNumberEdit(0, theme, 'Y', allowNegatives: true, allowDecimals: true, pixelWidth: VectorXYEditWidth, tabIndex: tabIndex)
{
TabIndex = tabIndex++,
SelectAllOnFocus = true,
VAnchor = VAnchor.Center,
Margin = theme.ButtonSpacing,
};
yEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
{
};
yEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
toolBar.AddChild(yEditWidget);
}
private void AddHomeButton(ThemeConfig theme, FlowLayoutWidget toolBar)
{
var homeButton = new ThemedIconButton(StaticData.Instance.LoadIcon("fa-home_16.png", 16, 16).GrayToColor(theme.TextColor), theme)
{
BackgroundColor = theme.SlightShade,
HoverColor = theme.SlightShade.WithAlpha(75),
@ -102,10 +173,7 @@ namespace MatterHackers.MatterControl.DesignTools
homeButton.Click += (s, e) =>
{
UiThread.RunOnIdle(() =>
{
ApplicationController.LaunchBrowser("https://www.matterhackers.com/store/c/3d-printer-filament");
});
CenterPartInView();
};
}
@ -115,6 +183,23 @@ namespace MatterHackers.MatterControl.DesignTools
private Affine ScalingTransform => Affine.NewScaling(layerScale, layerScale);
private Affine TotalTransform => Affine.NewTranslation(unscaledRenderOffset) * ScalingTransform * Affine.NewTranslation(Width / 2, Height / 2);
private int controlPointBeingDragged = -1;
private int controlPointBeingHovered = -1;
public void CenterPartInView()
{
if (vertexStorage != null)
{
var partBounds = vertexStorage.GetBounds();
var weightedCenter = partBounds.Center;
unscaledRenderOffset = -weightedCenter;
layerScale = Math.Min((Height - 30) / partBounds.Height, (Width - 30) / partBounds.Width);
Invalidate();
}
}
public override void OnDraw(Graphics2D graphics2D)
{
new VertexSourceApplyTransform(vertexStorage, TotalTransform).RenderCurve(graphics2D, theme.TextColor, 2, true, theme.PrimaryAccentColor.Blend(theme.TextColor, .5), theme.PrimaryAccentColor);
@ -127,22 +212,133 @@ namespace MatterHackers.MatterControl.DesignTools
base.OnMouseDown(mouseEvent);
if (MouseCaptured)
{
controlPointBeingDragged = -1;
mouseDownPosition.X = mouseEvent.X;
mouseDownPosition.Y = mouseEvent.Y;
lastMousePosition = mouseDownPosition;
mouseDownTransformOverride = TransformState;
// check if not left button
switch (mouseEvent.Button)
{
case MouseButtons.Left:
if (Keyboard.IsKeyDown(Keys.ControlKey))
{
if (Keyboard.IsKeyDown(Keys.Alt))
{
mouseDownTransformOverride = ETransformState.Scale;
}
else
{
mouseDownTransformOverride = ETransformState.Move;
}
}
else
{
// we are in edit mode, check if we are over any control points
controlPointBeingDragged = GetControlPointIndex(mouseEvent.Position);
}
break;
case MouseButtons.Middle:
mouseDownTransformOverride = ETransformState.Move;
break;
case MouseButtons.Right:
mouseDownTransformOverride = ETransformState.Scale;
break;
}
}
}
private int GetControlPointIndex(Vector2 mousePosition)
{
double hitThreshold = 10; // Threshold for considering a hit, in screen pixels
for (int i = 0; i < vertexStorage.Count; i++)
{
Vector2 controlPoint = vertexStorage[i].Position + unscaledRenderOffset;
ScalingTransform.transform(ref controlPoint);
// we center on the scren so we have to add that in after scaling
controlPoint += new Vector2(Width / 2, Height / 2);
if ((controlPoint - mousePosition).Length <= hitThreshold) // Check if the mouse position is within the threshold
{
return i; // Control point index
}
}
return -1; // No control point found at this position
}
public override void OnMouseMove(MouseEventArgs mouseEvent)
{
base.OnMouseMove(mouseEvent);
var mousePos = new Vector2(mouseEvent.X, mouseEvent.Y);
if (MouseCaptured)
{
DoTranslateAndZoom(mouseEvent);
if (controlPointBeingDragged > -1)
{
// we are dragging a control point
var mouseDelta = mouseEvent.Position - lastMousePosition;
if (mouseDelta.LengthSquared > 0)
{
ScalingTransform.inverse_transform(ref mouseDelta);
OffsetSelectedPoint(mouseDelta);
vertexChanged?.Invoke();
}
}
}
else
{
// highlight any contorl points we are over
}
lastMousePosition = mouseEvent.Position;
}
private void OffsetSelectedPoint(Vector2 delta)
{
if (controlPointBeingDragged < 0
|| controlPointBeingDragged >= vertexStorage.Count)
{
return;
}
var vertexData = vertexStorage[controlPointBeingDragged];
if (vertexData.Hint == CommandHint.C4Point)
{
for (int i = -1; i < 2; i++)
{
var pointIndex = controlPointBeingDragged + i;
// the prev point
if (pointIndex > 0
&& pointIndex < vertexStorage.Count)
{
var vertexData2 = vertexStorage[pointIndex];
vertexStorage[pointIndex] = new VertexData(vertexData2.Command, vertexData2.Position + delta, vertexData2.Hint);
}
}
}
else
{
// only drag the point
vertexStorage[controlPointBeingDragged] = new VertexData(vertexData.Command, vertexData.Position + delta, vertexData.Hint);
}
}
private void DoTranslateAndZoom(MouseEventArgs mouseEvent)
{
var mousePos = new Vector2(mouseEvent.X, mouseEvent.Y);
var mouseDelta = mousePos - lastMousePosition;
switch (TransformState)
switch (mouseDownTransformOverride)
{
case ETransformState.Scale:
double zoomDelta = 1;
@ -168,20 +364,20 @@ namespace MatterHackers.MatterControl.DesignTools
break;
case ETransformState.Move:
default: // also treat everything else like a move
ScalingTransform.inverse_transform(ref mouseDelta);
unscaledRenderOffset += mouseDelta;
scaleChanged?.Invoke(unscaledRenderOffset, layerScale);
break;
case ETransformState.Edit:
default: // also treat everything else like an edit
break;
}
Invalidate();
}
lastMousePosition = mousePos;
}
public override void OnMouseWheel(MouseEventArgs mouseEvent)
{
base.OnMouseWheel(mouseEvent);

View file

@ -31,7 +31,6 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
@ -59,8 +58,7 @@ namespace MatterHackers.MatterControl.DesignTools
Name = "Radial Pinch".Localize();
}
[PathEditorFactory.TopAndBottomMoveXOnly]
[PathEditorFactory.XMustBeGreaterThan0]
[PathEditorFactory.ShowAxis]
public PathEditorFactory.EditableVertexStorage PathForHorizontalOffsets { get; set; } = new PathEditorFactory.EditableVertexStorage();
[Description("Specifies the number of vertical cuts required to ensure the part can be pinched well.")]
@ -117,14 +115,6 @@ namespace MatterHackers.MatterControl.DesignTools
return AxisAlignedBoundingBox.CenteredBox(new Vector3(1, 1, sourceAabb.ZSize), center).NewTransformed(this.WorldMatrix());
}
public Vector2 Point1 { get; set; } = new Vector2(0, 0);
public Vector2 Point2 {get; set;} = new Vector2(1, 4);
public Vector2 Point3 { get; set;} = new Vector2(2, 8);
public Vector2 Point4 { get; set;} = new Vector2(3, 12);
public Vector2 Point5 { get; set;} = new Vector2(4, 14);
public Vector2 Point6 { get; set;} = new Vector2(5, 16);
public Vector2 Point7 { get; set;} = new Vector2(6, 18);
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
@ -174,13 +164,22 @@ namespace MatterHackers.MatterControl.DesignTools
var maxRadius = enclosingCircle.Radius + RotationOffset.Length;
//if (PathForHorizontalOffsets.Count == 0)
// if there is no path make a bad one
if (PathForHorizontalOffsets.Count == 0)
{
var bottomPoint = new Vector2(maxRadius, bottom * 10);
var topPoint = new Vector2(maxRadius, top * 10);
var middlePoint = (bottomPoint + topPoint) / 2;
middlePoint.X *= 2;
var Point1 = new Vector2(0, 0);
var Point2 = new Vector2(1, 4);
var Point3 = new Vector2(2, 8);
var Point4 = new Vector2(3, 12);
var Point5 = new Vector2(4, 14);
var Point6 = new Vector2(5, 16);
var Point7 = new Vector2(6, 18);
PathForHorizontalOffsets.Clear();
PathForHorizontalOffsets.MoveTo(Point1);
PathForHorizontalOffsets.Curve4(Point2, Point3, Point4);

View file

@ -28,9 +28,7 @@ either expressed or implied, of the FreeBSD Project.
*/
using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.MatterControl.DesignTools;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.SlicerConfiguration
@ -82,10 +80,11 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
xEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
{
this.SetValue(
string.Format("{0},{1}", xEditWidget.ActuallNumberEdit.Value.ToString("0.###"), yEditWidget.ActuallNumberEdit.Value.ToString("0.###")),
string.Format("{0},{1}",
xEditWidget.ActuallNumberEdit.Value.ToString("0.###"),
yEditWidget.ActuallNumberEdit.Value.ToString("0.###")),
userInitiated: true);
};
xEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
container.AddChild(xEditWidget);
@ -101,10 +100,11 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
yEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
{
this.SetValue(
string.Format("{0},{1}", xEditWidget.ActuallNumberEdit.Value.ToString("0.###"), yEditWidget.ActuallNumberEdit.Value.ToString("0.###")),
string.Format("{0},{1}",
xEditWidget.ActuallNumberEdit.Value.ToString("0.###"),
yEditWidget.ActuallNumberEdit.Value.ToString("0.###")),
userInitiated: true);
};
yEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
container.AddChild(yEditWidget);

View file

@ -88,6 +88,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
zEditWidget.ActuallNumberEdit.Value.ToString("0.###")),
userInitiated: true);
};
xEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
container.AddChild(xEditWidget);
@ -110,6 +111,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
zEditWidget.ActuallNumberEdit.Value.ToString("0.###")),
userInitiated: true);
};
yEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
container.AddChild(yEditWidget);
@ -132,6 +134,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
zEditWidget.ActuallNumberEdit.Value.ToString("0.###")),
userInitiated: true);
};
zEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
container.AddChild(zEditWidget);

@ -1 +1 @@
Subproject commit 4329e51c1d2a762a42176e1a1aac9bac43f02da6
Subproject commit 3c76fcb1852d66078ab527e5871dd8c62865680b