diff --git a/MatterControlLib/DesignTools/PublicPropertyEditor.cs b/MatterControlLib/DesignTools/PublicPropertyEditor.cs
index 215075908..527924c0f 100644
--- a/MatterControlLib/DesignTools/PublicPropertyEditor.cs
+++ b/MatterControlLib/DesignTools/PublicPropertyEditor.cs
@@ -308,18 +308,27 @@ namespace MatterHackers.MatterControl.DesignTools
}
//field.Content
- undoBuffer.AddAndDo(new UndoRedoActions(() =>
+ if (undoBuffer != null)
{
- property.SetValue(valueFromString(oldValue));
- object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
- propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
- },
- () =>
+ undoBuffer.AddAndDo(new UndoRedoActions(() =>
+ {
+ property.SetValue(valueFromString(oldValue));
+ object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
+ propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
+ },
+ () =>
+ {
+ property.SetValue(valueFromString(newValue));
+ object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
+ propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
+ }));
+ }
+ else
{
property.SetValue(valueFromString(newValue));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
- }));
+ }
};
}
diff --git a/MatterControlLib/DesignTools/SupportGenerator.cs b/MatterControlLib/DesignTools/SupportGenerator.cs
index 861ecc654..a280be52d 100644
--- a/MatterControlLib/DesignTools/SupportGenerator.cs
+++ b/MatterControlLib/DesignTools/SupportGenerator.cs
@@ -34,8 +34,6 @@ using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
-using MatterHackers.Agg.Transform;
-using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.PolygonMesh;
using MatterHackers.RayTracer;
@@ -88,6 +86,8 @@ namespace MatterHackers.MatterControl.DesignTools
this.scene = scene;
}
+ public enum SupportGenerationType { Normal, From_Bed }
+
public double MaxOverHangAngle
{
get
@@ -133,30 +133,30 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
+ public SupportGenerationType SupportType
+ {
+ get
+ {
+ var supportString = UserSettings.Instance.get(UserSettingsKey.SupportGenerationType);
+ if (Enum.TryParse(supportString, out SupportGenerationType supportType))
+ {
+ return supportType;
+ }
+
+ return SupportGenerationType.Normal;
+ }
+
+ set
+ {
+ UserSettings.Instance.set(UserSettingsKey.SupportGenerationType, value.ToString());
+ }
+ }
+
///
/// The amount to reduce the pillars so they are separated in the 3D view
///
private double reduceAmount => .99;
- // function to get all the columns that need support generation
- IEnumerable<(int x, int y)> GetSupportCorrodinates(ImageBuffer supportNeededImage)
- {
- var buffer = supportNeededImage.GetBuffer();
- // check if the image has any alpha set to something other than 255
- for (int y = 0; y < supportNeededImage.Height; y++)
- {
- var yOffset = supportNeededImage.GetBufferOffsetY(y);
- for (int x = 0; x < supportNeededImage.Width; x++)
- {
- // get the alpha at this pixel
- //if (buffer[yOffset + x] > 0)
- {
- yield return (x, y);
- }
- }
- }
- }
-
public Task Create(IProgress progress, CancellationToken cancelationToken)
{
ProgressStatus status = new ProgressStatus();
@@ -177,8 +177,7 @@ namespace MatterHackers.MatterControl.DesignTools
AxisAlignedBoundingBox allBounds = AxisAlignedBoundingBox.Empty();
foreach (var candidate in supportCandidates)
{
- var matrix = candidate.WorldMatrix(scene);
- allBounds += candidate.GetAxisAlignedBoundingBox();
+ allBounds += candidate.GetAxisAlignedBoundingBox(candidate.Matrix.Inverted * candidate.WorldMatrix());
}
// create the gird of possible support
@@ -223,204 +222,6 @@ namespace MatterHackers.MatterControl.DesignTools
return Task.CompletedTask;
}
- int GetNextTop(int i, List<(double z, bool bottom)> planes)
- {
- while (i < planes.Count
- && planes[i].bottom)
- {
- i++;
- }
-
- return i;
- }
-
- int GetNextBottom(int i, List<(double z, bool bottom)> planes)
- {
- // first skip all the tops
- while (i < planes.Count
- && !planes[i].bottom)
- {
- i++;
- }
-
- // then look for the last bottom before next top
- while (i < planes.Count
- && planes[i].bottom
- && planes.Count > i + 1
- && planes[i + 1].bottom)
- {
- i++;
- }
-
- return i;
- }
-
- private void AddSupportColumns(RectangleDouble gridBounds, Dictionary<(int x, int y), List<(double z, bool bottom)>> detectedPlanes)
- {
- IObject3D supportColumnsToAdd = new Object3D();
- bool fromBed = false;
- foreach (var kvp in detectedPlanes)
- {
- if(kvp.Value.Count == 0)
- {
- continue;
- }
-
- int i = 0;
-
- kvp.Value.Sort((a, b) =>
- {
- return a.z.CompareTo(b.z);
- });
-
- var yPos = (gridBounds.Bottom + kvp.Key.y) * PillarSize;
- var xPos = (gridBounds.Left + kvp.Key.x) * PillarSize;
-
- if (fromBed)
- {
- i = GetNextBottom(i, kvp.Value);
- if (kvp.Value[i].bottom)
- {
- AddSupportColumn(supportColumnsToAdd, xPos, yPos, 0, kvp.Value[i].z);
- }
- }
- else
- {
- double lastTopZ = 0;
- int lastBottom = i;
- do
- {
- // if the first plane is a top, move to the last top before we find a bottom
- if(i == 0
- && !kvp.Value[i].bottom)
- {
- i = GetNextTop(i + 1, kvp.Value);
- if (i < kvp.Value.Count)
- {
- lastTopZ = kvp.Value[i].z;
- }
- }
- lastBottom = i;
- // find all open arreas in the list and add support
- i = GetNextBottom(i, kvp.Value);
- if (i < kvp.Value.Count
- && kvp.Value[i].bottom)
- {
- AddSupportColumn(supportColumnsToAdd, xPos, yPos, lastTopZ, kvp.Value[i].z);
- }
- i = GetNextTop(i+1, kvp.Value);
- if (i < kvp.Value.Count)
- {
- lastTopZ = kvp.Value[i].z;
- }
- } while (i != lastBottom && i < kvp.Value.Count);
- }
- }
-
- scene.Children.Modify(list =>
- {
- list.AddRange(supportColumnsToAdd.Children);
- });
- }
-
- private Dictionary<(int x, int y), List<(double z, bool bottom)>> DetectRequiredSupportByTracing(RectangleDouble gridBounds, IEnumerable supportCandidates)
- {
- var traceData = GetTraceData(supportCandidates);
-
- // keep a list of all the detected planes in each support column
- var detectedPlanes = new Dictionary<(int x, int y), List<(double z, bool bottom)>>();
-
- int gridWidth = (int)gridBounds.Width;
- int gridHeight = (int)gridBounds.Height;
-
- // at the center of every grid item add in a list of all the top faces to look down from
- for (int y = 0; y < gridHeight; y++)
- {
- for (int x = 0; x < gridWidth; x++)
- {
- IntersectInfo upHit = null;
-
- for (double yOffset = -1; yOffset <= 1; yOffset++)
- {
- for (double xOffset = -1; xOffset <= 1; xOffset++)
- {
- var yPos = (gridBounds.Bottom + y) * PillarSize + (yOffset * PillarSize / 2);
- var xPos = (gridBounds.Left + x) * PillarSize + (xOffset * PillarSize / 2);
-
- var upRay = new Ray(new Vector3(xPos + .000013, yPos - .00027, 0), Vector3.UnitZ, intersectionType: IntersectionType.Both);
- do
- {
- upHit = traceData.GetClosestIntersection(upRay);
- if (upHit != null)
- {
- if (!detectedPlanes.ContainsKey((x, y)))
- {
- detectedPlanes.Add((x, y), new List<(double z, bool bottom)>());
- }
-
- detectedPlanes[(x, y)].Add((upHit.HitPosition.Z, upHit.normalAtHit.Z < 0));
-
- // make a new ray just past the last hit to keep looking for up hits
- upRay = new Ray(new Vector3(xPos, yPos, upHit.HitPosition.Z + .001), Vector3.UnitZ, intersectionType: IntersectionType.Both);
- }
- } while (upHit != null);
- }
- }
- }
- }
-
- return detectedPlanes;
- }
-
- private IPrimitive GetTraceData(IEnumerable supportCandidates)
- {
- List supportVerts;
- FaceList supportFaces;
-
- // find all the faces that are candidates for support
- supportVerts = new List();
- supportFaces = new FaceList();
- foreach (var item in supportCandidates)
- {
- // add all the down faces to supportNeededImage
- var matrix = item.WorldMatrix(scene);
- for (int faceIndex = 0; faceIndex < item.Mesh.Faces.Count; faceIndex++)
- {
- var face0Normal = item.Mesh.Faces[faceIndex].normal.TransformNormal(matrix).GetNormal();
- var angle = MathHelper.RadiansToDegrees(Math.Acos(face0Normal.Dot(-Vector3Float.UnitZ)));
-
- // check if the face is pointing in the up direction at all
- bool isUpFace = angle > 90;
-
- // check if the face is pointing down
-
- if (angle < MaxOverHangAngle
- || isUpFace)
- {
- var face = item.Mesh.Faces[faceIndex];
- var verts = new int[] { face.v0, face.v1, face.v2 };
- var p0 = item.Mesh.Vertices[face.v0].Transform(matrix);
- var p1 = item.Mesh.Vertices[face.v1].Transform(matrix);
- var p2 = item.Mesh.Vertices[face.v2].Transform(matrix);
- var vc = supportVerts.Count;
- supportVerts.Add(p0);
- supportVerts.Add(p1);
- supportVerts.Add(p2);
-
- supportFaces.Add(vc, vc + 1, vc + 2, face0Normal);
- }
- }
-
- // add all mesh edges that need support
-
- // add all unsupported vertices (low points of a face group that individually do not need support)
- }
-
- return supportFaces.CreateTraceData(supportVerts);
- }
-
- public Agg.UI.HAnchor SupportType { get; set; } = Agg.UI.HAnchor.Fit;
-
public void RemoveExisting()
{
var existingSupports = scene.Children.Where(i => i.GetType() == typeof(GeneratedSupportObject3D));
@@ -493,5 +294,222 @@ namespace MatterHackers.MatterControl.DesignTools
holder.Children.Add(support);
}
+
+ private void AddSupportColumns(RectangleDouble gridBounds, Dictionary<(int x, int y), List<(double z, bool bottom)>> detectedPlanes)
+ {
+ IObject3D supportColumnsToAdd = new Object3D();
+ bool fromBed = SupportType == SupportGenerationType.From_Bed;
+ var halfPillar = PillarSize / 2;
+ foreach (var kvp in detectedPlanes)
+ {
+ if (kvp.Value.Count == 0)
+ {
+ continue;
+ }
+
+ int i = 0;
+
+ kvp.Value.Sort((a, b) =>
+ {
+ return a.z.CompareTo(b.z);
+ });
+
+ var yPos = (gridBounds.Bottom + kvp.Key.y) * PillarSize + halfPillar;
+ var xPos = (gridBounds.Left + kvp.Key.x) * PillarSize + halfPillar;
+
+ if (fromBed)
+ {
+ i = GetNextBottom(i, kvp.Value);
+ if (kvp.Value[i].bottom)
+ {
+ AddSupportColumn(supportColumnsToAdd, xPos, yPos, 0, kvp.Value[i].z);
+ }
+ }
+ else
+ {
+ double lastTopZ = 0;
+ int lastBottom = i;
+ do
+ {
+ // if the first plane is a top, move to the last top before we find a bottom
+ if (i == 0
+ && !kvp.Value[i].bottom)
+ {
+ i = GetNextTop(i + 1, kvp.Value);
+ if (i < kvp.Value.Count)
+ {
+ lastTopZ = kvp.Value[i].z;
+ }
+ }
+ lastBottom = i;
+ // find all open arreas in the list and add support
+ i = GetNextBottom(i, kvp.Value);
+ if (i < kvp.Value.Count
+ && kvp.Value[i].bottom)
+ {
+ AddSupportColumn(supportColumnsToAdd, xPos, yPos, lastTopZ, kvp.Value[i].z);
+ }
+ i = GetNextTop(i + 1, kvp.Value);
+ if (i < kvp.Value.Count)
+ {
+ lastTopZ = kvp.Value[i].z;
+ }
+ } while (i != lastBottom && i < kvp.Value.Count);
+ }
+ }
+
+ scene.Children.Modify(list =>
+ {
+ list.AddRange(supportColumnsToAdd.Children);
+ });
+ }
+
+ private Dictionary<(int x, int y), List<(double z, bool bottom)>> DetectRequiredSupportByTracing(RectangleDouble gridBounds, IEnumerable supportCandidates)
+ {
+ var traceData = GetTraceData(supportCandidates);
+
+ // keep a list of all the detected planes in each support column
+ var detectedPlanes = new Dictionary<(int x, int y), List<(double z, bool bottom)>>();
+
+ int gridWidth = (int)gridBounds.Width;
+ int gridHeight = (int)gridBounds.Height;
+
+ // at the center of every grid item add in a list of all the top faces to look down from
+ for (int y = 0; y < gridHeight; y++)
+ {
+ for (int x = 0; x < gridWidth; x++)
+ {
+ IntersectInfo upHit = null;
+
+ for (double yOffset = -1; yOffset <= 1; yOffset++)
+ {
+ for (double xOffset = -1; xOffset <= 1; xOffset++)
+ {
+ var halfPillar = PillarSize / 2;
+ var yPos = (gridBounds.Bottom + y) * PillarSize + halfPillar + (yOffset * halfPillar);
+ var xPos = (gridBounds.Left + x) * PillarSize + halfPillar + (xOffset * halfPillar);
+
+ var upRay = new Ray(new Vector3(xPos + .000013, yPos - .00027, 0), Vector3.UnitZ, intersectionType: IntersectionType.Both);
+ do
+ {
+ upHit = traceData.GetClosestIntersection(upRay);
+ if (upHit != null)
+ {
+ if (!detectedPlanes.ContainsKey((x, y)))
+ {
+ detectedPlanes.Add((x, y), new List<(double z, bool bottom)>());
+ }
+
+ detectedPlanes[(x, y)].Add((upHit.HitPosition.Z, upHit.normalAtHit.Z < 0));
+
+ // make a new ray just past the last hit to keep looking for up hits
+ upRay = new Ray(new Vector3(xPos, yPos, upHit.HitPosition.Z + .001), Vector3.UnitZ, intersectionType: IntersectionType.Both);
+ }
+ } while (upHit != null);
+ }
+ }
+ }
+ }
+
+ return detectedPlanes;
+ }
+
+ private int GetNextBottom(int i, List<(double z, bool bottom)> planes)
+ {
+ // first skip all the tops
+ while (i < planes.Count
+ && !planes[i].bottom)
+ {
+ i++;
+ }
+
+ // then look for the last bottom before next top
+ while (i < planes.Count
+ && planes[i].bottom
+ && planes.Count > i + 1
+ && planes[i + 1].bottom)
+ {
+ i++;
+ }
+
+ return i;
+ }
+
+ private int GetNextTop(int i, List<(double z, bool bottom)> planes)
+ {
+ while (i < planes.Count
+ && planes[i].bottom)
+ {
+ i++;
+ }
+
+ return i;
+ }
+
+ // function to get all the columns that need support generation
+ private IEnumerable<(int x, int y)> GetSupportCorrodinates(ImageBuffer supportNeededImage)
+ {
+ var buffer = supportNeededImage.GetBuffer();
+ // check if the image has any alpha set to something other than 255
+ for (int y = 0; y < supportNeededImage.Height; y++)
+ {
+ var yOffset = supportNeededImage.GetBufferOffsetY(y);
+ for (int x = 0; x < supportNeededImage.Width; x++)
+ {
+ // get the alpha at this pixel
+ //if (buffer[yOffset + x] > 0)
+ {
+ yield return (x, y);
+ }
+ }
+ }
+ }
+
+ private IPrimitive GetTraceData(IEnumerable supportCandidates)
+ {
+ List supportVerts;
+ FaceList supportFaces;
+
+ // find all the faces that are candidates for support
+ supportVerts = new List();
+ supportFaces = new FaceList();
+ foreach (var item in supportCandidates)
+ {
+ // add all the down faces to supportNeededImage
+ var matrix = item.WorldMatrix(scene);
+ for (int faceIndex = 0; faceIndex < item.Mesh.Faces.Count; faceIndex++)
+ {
+ var face0Normal = item.Mesh.Faces[faceIndex].normal.TransformNormal(matrix).GetNormal();
+ var angle = MathHelper.RadiansToDegrees(Math.Acos(face0Normal.Dot(-Vector3Float.UnitZ)));
+
+ // check if the face is pointing in the up direction at all
+ bool isUpFace = angle > 90;
+
+ // check if the face is pointing down
+
+ if (angle < MaxOverHangAngle
+ || isUpFace)
+ {
+ var face = item.Mesh.Faces[faceIndex];
+ var verts = new int[] { face.v0, face.v1, face.v2 };
+ var p0 = item.Mesh.Vertices[face.v0].Transform(matrix);
+ var p1 = item.Mesh.Vertices[face.v1].Transform(matrix);
+ var p2 = item.Mesh.Vertices[face.v2].Transform(matrix);
+ var vc = supportVerts.Count;
+ supportVerts.Add(p0);
+ supportVerts.Add(p1);
+ supportVerts.Add(p2);
+
+ supportFaces.Add(vc, vc + 1, vc + 2, face0Normal);
+ }
+ }
+
+ // add all mesh edges that need support
+
+ // add all unsupported vertices (low points of a face group that individually do not need support)
+ }
+
+ return supportFaces.CreateTraceData(supportVerts);
+ }
}
}
\ No newline at end of file
diff --git a/MatterControlLib/PartPreviewWindow/GenerateSupportPanel.cs b/MatterControlLib/PartPreviewWindow/GenerateSupportPanel.cs
index 745541421..6fd1c9ef1 100644
--- a/MatterControlLib/PartPreviewWindow/GenerateSupportPanel.cs
+++ b/MatterControlLib/PartPreviewWindow/GenerateSupportPanel.cs
@@ -61,9 +61,20 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.BackgroundColor = theme.BackgroundColor;
this.Padding = theme.DefaultContainerPadding;
- // put in support pillar size
+ // Add an editor field for the SupportGenerator.SupportType
+ PropertyInfo propertyInfo = typeof(SupportGenerator).GetProperty(nameof(SupportGenerator.SupportType));
- // support pillar resolution
+ var editor = PublicPropertyEditor.CreatePropertyEditor(
+ new EditableProperty(propertyInfo, supportGenerator),
+ null,
+ new PPEContext(),
+ theme);
+ if (editor != null)
+ {
+ this.AddChild(editor);
+ }
+
+ // put in support pillar size
var pillarSizeField = new DoubleField(theme);
pillarSizeField.Initialize(0);
pillarSizeField.DoubleValue = supportGenerator.PillarSize;
@@ -99,19 +110,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
overHangRow.AddChild(overHangField.Content);
this.AddChild(overHangRow);
- // Add an editor field for the SupportGenerator.SupportType
- PropertyInfo propertyInfo = typeof(SupportGenerator).GetProperty(nameof(SupportGenerator.SupportType));
-
- var editor = PublicPropertyEditor.CreatePropertyEditor(
- new EditableProperty(propertyInfo, supportGenerator),
- null,
- new PPEContext(),
- theme);
- if (editor != null)
- {
- this.AddChild(editor);
- }
-
// Button Row
var buttonRow = new FlowLayoutWidget()
{
diff --git a/MatterControlLib/SettingsManagement/UserSettings.cs b/MatterControlLib/SettingsManagement/UserSettings.cs
index 52e9a31d0..69d680726 100644
--- a/MatterControlLib/SettingsManagement/UserSettings.cs
+++ b/MatterControlLib/SettingsManagement/UserSettings.cs
@@ -44,6 +44,7 @@ namespace MatterHackers.MatterControl
public const string NotificationEmailAddress = nameof(NotificationEmailAddress);
public const string NotificationPhoneNumber = nameof(NotificationPhoneNumber);
public const string OpenScadPath = nameof(OpenScadPath);
+ public const string SupportGenerationType = nameof(SupportGenerationType);
public const string SupportMaxOverHangAngle = nameof(SupportMaxOverHangAngle);
public const string SupportPillarSize = nameof(SupportPillarSize);
public const string PopupLibraryWidth = nameof(PopupLibraryWidth);