From 959e6ee5d52752cf810f0fb99af65b8a39b04342 Mon Sep 17 00:00:00 2001 From: Lars Brubaker Date: Thu, 19 Aug 2021 08:46:31 -0700 Subject: [PATCH 1/4] working to improve property editor tabs --- .../UIFields/EnumDisplayField.cs | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs b/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs index 00e3085c2..280ab6f63 100644 --- a/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs +++ b/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs @@ -109,11 +109,51 @@ namespace MatterHackers.MatterControl.SlicerConfiguration } } + private static void EnableReduceWidth(GuiWidget enumTab, int minSize) + { + var deviceScale = GuiWidget.DeviceScale; + enumTab.MinimumSize = new Vector2(minSize * deviceScale, enumTab.Height); + enumTab.HAnchor = HAnchor.Stretch; + + // delay this for an update so that the layout of the text widget has happened and its size has been updated. + var textWidget = enumTab.Descendants().First(); + textWidget.TextChanged += (s, e) => UiThread.RunOnIdle(UpadetMaxWidth); + + UpadetMaxWidth(); + + void UpadetMaxWidth() + { + // the text + var width = textWidget.Width + enumTab.Margin.Width * deviceScale; + enumTab.MaximumSize = new Vector2(width, enumTab.MaximumSize.Y); + enumTab.Width -= 1; + + if (string.IsNullOrEmpty(enumTab.ToolTipText)) + { + // wait for this size change to take effect and update the tool tip + enumTab.BoundsChanged += (s, e) => + { + if (enumTab.Width < enumTab.MaximumSize.X) + { + enumTab.ToolTipText = textWidget.Text; + } + else + { + enumTab.ToolTipText = ""; + } + }; + } + } + + enumTab.HAnchor = HAnchor.Stretch; + } + private void AddTabs(IEnumerable<(string Key, string Value)> enumItems, List descriptions) { var menuRow = new FlowLayoutWidget() { - Margin = 5 + Margin = 5, + HAnchor = HAnchor.Stretch, }; int index = 0; @@ -123,7 +163,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration var radioButton = new RadioTextButton(enumItem.Value, theme) { - ToolTipText = descriptions[index] + ToolTipText = descriptions[index], + Margin = new BorderDouble(9, 0), + Padding = 0, }; menuRow.AfterDraw += (s, e) => @@ -145,7 +187,16 @@ namespace MatterHackers.MatterControl.SlicerConfiguration radioButton.Checked = true; } - menuRow.AddChild(radioButton); + var container = new FlowLayoutWidget() + { + HAnchor = HAnchor.Stretch, + }; + + container.AddChild(radioButton); + + EnableReduceWidth(container, 40); + + menuRow.AddChild(container); var localItem = enumItem; radioButton.CheckedStateChanged += (s, e) => From ffeb157e9037f63195c8f271886326e41bcf160f Mon Sep 17 00:00:00 2001 From: LarsBrubaker Date: Thu, 19 Aug 2021 21:02:41 -0700 Subject: [PATCH 2/4] Make the property tabs able to shrink and look good --- .../UIFields/EnumDisplayField.cs | 80 +++++++++++-------- Submodules/MatterSlice | 2 +- Submodules/agg-sharp | 2 +- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs b/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs index 280ab6f63..9ee75cc80 100644 --- a/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs +++ b/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs @@ -109,40 +109,64 @@ namespace MatterHackers.MatterControl.SlicerConfiguration } } - private static void EnableReduceWidth(GuiWidget enumTab, int minSize) + private void EnableReduceWidth(RadioTextButton enumTab) { var deviceScale = GuiWidget.DeviceScale; - enumTab.MinimumSize = new Vector2(minSize * deviceScale, enumTab.Height); + var padingSize = enumTab.Padding.Left * deviceScale; + enumTab.MinimumSize = new Vector2(padingSize * 3, enumTab.Height); enumTab.HAnchor = HAnchor.Stretch; // delay this for an update so that the layout of the text widget has happened and its size has been updated. var textWidget = enumTab.Descendants().First(); - textWidget.TextChanged += (s, e) => UiThread.RunOnIdle(UpadetMaxWidth); + textWidget.Margin = new BorderDouble(enumTab.Padding.Left, 0, 0, 0); + textWidget.HAnchor = HAnchor.Left; - UpadetMaxWidth(); - - void UpadetMaxWidth() + enumTab.AfterDraw += (s, e) => { - // the text - var width = textWidget.Width + enumTab.Margin.Width * deviceScale; - enumTab.MaximumSize = new Vector2(width, enumTab.MaximumSize.Y); - enumTab.Width -= 1; - - if (string.IsNullOrEmpty(enumTab.ToolTipText)) + if (enumTab.Width < enumTab.MaximumSize.X) { - // wait for this size change to take effect and update the tool tip - enumTab.BoundsChanged += (s, e) => + var bounds = enumTab.LocalBounds; + var g = e.Graphics2D; + var color = enumTab.SelectedBackgroundColor; + if (!enumTab.Checked) { - if (enumTab.Width < enumTab.MaximumSize.X) + foreach (var parent in enumTab.Parents()) { - enumTab.ToolTipText = textWidget.Text; + if (parent.BackgroundColor.alpha > 200) + { + color = parent.BackgroundColor; + break; + } } - else - { - enumTab.ToolTipText = ""; - } - }; + } + // cover the text with an alpha mask + for (int i = 0; i < padingSize + 1; i++) + { + var x = bounds.Right - padingSize + i; + g.Line(x, bounds.Bottom, x, bounds.Top, color.WithAlpha(Math.Min(255, i / 10.0 * deviceScale))); + } } + }; + + // the text + var maxWidth = textWidget.Width + enumTab.Padding.Width * deviceScale; + enumTab.MaximumSize = new Vector2(maxWidth, enumTab.MaximumSize.Y); + enumTab.Padding = new BorderDouble(0, enumTab.Padding.Bottom, 0, enumTab.Padding.Top); + + if (string.IsNullOrEmpty(enumTab.ToolTipText)) + { + // wait for this size change to take effect and update the tool tip + enumTab.BoundsChanged += (s, e) => + { + if (enumTab.Width < enumTab.MaximumSize.X) + { + enumTab.ToolTipText = textWidget.Text; + } + else + { + enumTab.ToolTipText = ""; + } + }; } enumTab.HAnchor = HAnchor.Stretch; @@ -153,7 +177,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration var menuRow = new FlowLayoutWidget() { Margin = 5, - HAnchor = HAnchor.Stretch, }; int index = 0; @@ -164,8 +187,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration var radioButton = new RadioTextButton(enumItem.Value, theme) { ToolTipText = descriptions[index], - Margin = new BorderDouble(9, 0), - Padding = 0, }; menuRow.AfterDraw += (s, e) => @@ -187,16 +208,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration radioButton.Checked = true; } - var container = new FlowLayoutWidget() - { - HAnchor = HAnchor.Stretch, - }; + EnableReduceWidth(radioButton); - container.AddChild(radioButton); - - EnableReduceWidth(container, 40); - - menuRow.AddChild(container); + menuRow.AddChild(radioButton); var localItem = enumItem; radioButton.CheckedStateChanged += (s, e) => diff --git a/Submodules/MatterSlice b/Submodules/MatterSlice index cfdb25b9b..adb494612 160000 --- a/Submodules/MatterSlice +++ b/Submodules/MatterSlice @@ -1 +1 @@ -Subproject commit cfdb25b9b6564ff8039777531656a162fd2cae99 +Subproject commit adb494612051827f20328a624bee101559d6ace5 diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index 07f063560..0e6c40749 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit 07f063560762f7762553f6cd67de90ed89fd8463 +Subproject commit 0e6c407494ab8a587e950ed5e544c0404b1edd71 From c2a8ed5762d67d4eacb2b26f85a84cfb20379fa4 Mon Sep 17 00:00:00 2001 From: Lars Brubaker Date: Fri, 20 Aug 2021 09:57:38 -0700 Subject: [PATCH 3/4] New ImageConverter has reached first ship candidate --- .../ApplicationView/SceneOperations.cs | 2 - .../DesignTools/Attributes/SliderAttribute.cs | 48 +++++++++++++++++++ .../DesignTools/LithophaneObject3D.cs | 2 +- .../DesignTools/Obsolete/CurveObject3D.cs | 4 +- .../DesignTools/Operations/CurveObject3D_2.cs | 4 +- .../DesignTools/Operations/CurveObject3D_3.cs | 4 +- .../Operations/Image/ImageToPathObject3D.cs | 4 +- .../Operations/Image/ImageToPathObject3D_2.cs | 47 +++++++++++++----- .../PartPreviewWindow/SelectedObjectPanel.cs | 6 ++- 9 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 MatterControlLib/DesignTools/Attributes/SliderAttribute.cs diff --git a/MatterControlLib/ApplicationView/SceneOperations.cs b/MatterControlLib/ApplicationView/SceneOperations.cs index 922469221..480700aed 100644 --- a/MatterControlLib/ApplicationView/SceneOperations.cs +++ b/MatterControlLib/ApplicationView/SceneOperations.cs @@ -322,8 +322,6 @@ namespace MatterHackers.MatterControl "$.Children.Children.Children.Children.AnalysisType", "$.Children.Children.Children.Children.TransparencyMessage", "$.Children.Children.Children.Children.Histogram", - "$.Children.Children.Height", - "$.Children.Children.Children.SmoothDistance", "$.Children", } }; diff --git a/MatterControlLib/DesignTools/Attributes/SliderAttribute.cs b/MatterControlLib/DesignTools/Attributes/SliderAttribute.cs new file mode 100644 index 000000000..f82742540 --- /dev/null +++ b/MatterControlLib/DesignTools/Attributes/SliderAttribute.cs @@ -0,0 +1,48 @@ +/* +Copyright (c) 2018, Lars Brubaker, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using System; + +namespace MatterHackers.MatterControl.DesignTools +{ + [AttributeUsage(AttributeTargets.Property)] + public class SliderAttribute : Attribute + { + public SliderAttribute(double min, double max, double increment) + { + this.Min = min; + this.Max = max; + this.Incement = increment; + } + + public double Min { get; set; } + public double Max { get; set; } + public double Incement { get; set; } + } +} \ No newline at end of file diff --git a/MatterControlLib/DesignTools/LithophaneObject3D.cs b/MatterControlLib/DesignTools/LithophaneObject3D.cs index c2677bdd0..2d4c54479 100644 --- a/MatterControlLib/DesignTools/LithophaneObject3D.cs +++ b/MatterControlLib/DesignTools/LithophaneObject3D.cs @@ -57,7 +57,7 @@ namespace MatterHackers.MatterControl.Plugins.Lithophane [DisplayName("Pixels Per mm"), Range(0.5, 3, ErrorMessage = "Value for {0} must be between {1} and {2}.")] public double PixelsPerMM { get; set; } = 1.5; - [Range(0.5, 3, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Slider(0.5, 3, .2)] public double Height { get; set; } = 2.5; public int Width { get; set; } = 150; diff --git a/MatterControlLib/DesignTools/Obsolete/CurveObject3D.cs b/MatterControlLib/DesignTools/Obsolete/CurveObject3D.cs index d735969c8..e6eb9373d 100644 --- a/MatterControlLib/DesignTools/Obsolete/CurveObject3D.cs +++ b/MatterControlLib/DesignTools/Obsolete/CurveObject3D.cs @@ -68,11 +68,11 @@ namespace MatterHackers.MatterControl.DesignTools public double Diameter { get; set; } = double.MinValue; - [Range(3, 360, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Slider(3, 360, 1)] [Description("Ensures the rotated part has a minimum number of sides per complete rotation")] public double MinSidesPerRotation { get; set; } = 3; - [Range(0, 100, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Slider(0, 100, 1)] [Description("Where to start the bend as a percent of the width of the part")] public double StartPercent { get; set; } = 50; diff --git a/MatterControlLib/DesignTools/Operations/CurveObject3D_2.cs b/MatterControlLib/DesignTools/Operations/CurveObject3D_2.cs index c5d4f2e72..908622cc3 100644 --- a/MatterControlLib/DesignTools/Operations/CurveObject3D_2.cs +++ b/MatterControlLib/DesignTools/Operations/CurveObject3D_2.cs @@ -64,11 +64,11 @@ namespace MatterHackers.MatterControl.DesignTools public double Diameter { get; set; } = double.MaxValue; - [Range(3, 360, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Slider(3, 360, 1)] [Description("Ensures the rotated part has a minimum number of sides per complete rotation")] public double MinSidesPerRotation { get; set; } = 30; - [Range(0, 100, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Slider(0, 100, 1)] [Description("Where to start the bend as a percent of the width of the part")] public double StartPercent { get; set; } = 50; diff --git a/MatterControlLib/DesignTools/Operations/CurveObject3D_3.cs b/MatterControlLib/DesignTools/Operations/CurveObject3D_3.cs index 0cce436ba..7fe5853db 100644 --- a/MatterControlLib/DesignTools/Operations/CurveObject3D_3.cs +++ b/MatterControlLib/DesignTools/Operations/CurveObject3D_3.cs @@ -86,7 +86,7 @@ namespace MatterHackers.MatterControl.DesignTools [DescriptionImage("https://lh3.googleusercontent.com/h-s2FyBKO5etYDr_9YSLtGmGmQTcmSGMu4p0mRqX4_7Z62Ndn2QRLoFICC6X9scbhr1EP29RiYRj4EmhLMUwiNTAG-PIiFbzI_jAses")] public BendDirections BendDirection { get; set; } = BendDirections.Bend_Up; - [Range(0, 100, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Slider(0, 100, 1)] [Description("Where to start the bend as a percent from the left side")] [DescriptionImage("https://lh3.googleusercontent.com/eOeWjr98uz_E924PnNaXrasepv15nWEuvhqH-jbaQyvrOVdX5MHXF00HdZQGC8NLpJc9ok1sToMtyPx1wnnDgFwTTGA5MjoMFu612AY1")] public double StartPercent { get; set; } = 50; @@ -95,7 +95,7 @@ namespace MatterHackers.MatterControl.DesignTools [Description("Split the mesh so it has enough geometry to create a smooth curve")] public bool SplitMesh { get; set; } = true; - [Range(3, 360, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Slider(3, 360, 1)] [Description("Ensures the rotated part has a minimum number of sides per complete rotation")] [DescriptionImage("https://lh3.googleusercontent.com/p9MyKu3AFP55PnobUKZQPqf6iAx11GzXyX-25f1ddrUnfCt8KFGd1YtHOR5HqfO0mhlX2ZVciZV4Yn0Kzfm43SErOS_xzgsESTu9scux")] public double MinSidesPerRotation { get; set; } = 30; diff --git a/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D.cs b/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D.cs index 47fd2ff6e..957524931 100644 --- a/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D.cs +++ b/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D.cs @@ -173,10 +173,10 @@ namespace MatterHackers.MatterControl.DesignTools [JsonIgnore] private ImageBuffer Image => this.Descendants().FirstOrDefault()?.Image; - [Range(0, 1, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Slider(0, 1, .05)] public DoubleOrExpression RangeStart { get; set; } = .1; - [Range(0, 1, ErrorMessage = "Value for {0} must be between {1} and {2}.")] + [Slider(0, 1, .05)] public DoubleOrExpression RangeEnd { get; set; } = 1; public IVertexSource VertexSource { get; set; } = new VertexStorage(); diff --git a/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D_2.cs b/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D_2.cs index 76a093256..a1f398f7b 100644 --- a/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D_2.cs +++ b/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D_2.cs @@ -116,7 +116,7 @@ namespace MatterHackers.MatterControl.DesignTools } - private AnalysisTypes _featureDetector = AnalysisTypes.Intensity; + private AnalysisTypes _featureDetector = AnalysisTypes.Intensity; [EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Tabs)] public AnalysisTypes AnalysisType { @@ -162,6 +162,10 @@ namespace MatterHackers.MatterControl.DesignTools [DisplayName("Select Range")] public Histogram Histogram { get; set; } = new Histogram(); + [Slider(0, 10, 1)] + [Description("The minimum area each loop needs to be for inclusion")] + public double MinSurfaceArea {get; set; } = 1; + public IVertexSource VertexSource { get; set; } = new VertexStorage(); public void AddObject3DControls(Object3DControlsLayer object3DControlsLayer) @@ -181,7 +185,7 @@ namespace MatterHackers.MatterControl.DesignTools this.FlattenToPathObject(undoBuffer); } - public void GenerateMarchingSquaresAndLines(Action progressReporter, ImageBuffer image, IThresholdFunction thresholdFunction) + public void GenerateMarchingSquaresAndLines(Action progressReporter, ImageBuffer image, IThresholdFunction thresholdFunction, int minimumSurfaceArea) { if (image != null) { @@ -200,34 +204,48 @@ namespace MatterHackers.MatterControl.DesignTools int pixelsToIntPointsScale = 1000; var lineLoops = marchingSquaresData.CreateLineLoops(pixelsToIntPointsScale); + if (minimumSurfaceArea > 0) + { + for(int i=lineLoops.Count - 1; i >=0; i--) + { + var area = Math.Abs(Clipper.Area(lineLoops[i])); + if (area < minimumSurfaceArea) + { + lineLoops.RemoveAt(i); + } + } + } + progressReporter?.Invoke(.15, null); var min = new IntPoint(-10, -10); var max = new IntPoint(10 + image.Width * pixelsToIntPointsScale, 10 + image.Height * pixelsToIntPointsScale); - var boundingPoly = new Polygon(); - boundingPoly.Add(min); - boundingPoly.Add(new IntPoint(min.X, max.Y)); - boundingPoly.Add(max); - boundingPoly.Add(new IntPoint(max.X, min.Y)); + var boundingPoly = new Polygon + { + min, + new IntPoint(min.X, max.Y), + max, + new IntPoint(max.X, min.Y) + }; // now clip the polygons to get the inside and outside polys var clipper = new Clipper(); clipper.AddPaths(lineLoops, PolyType.ptSubject, true); clipper.AddPath(boundingPoly, PolyType.ptClip, true); - var polygonShape = new Polygons(); + var polygonShapes = new Polygons(); progressReporter?.Invoke(.3, null); - clipper.Execute(ClipType.ctIntersection, polygonShape); + clipper.Execute(ClipType.ctIntersection, polygonShapes); progressReporter?.Invoke(.55, null); - polygonShape = Clipper.CleanPolygons(polygonShape, 100); + polygonShapes = Clipper.CleanPolygons(polygonShapes, 100); progressReporter?.Invoke(.75, null); - VertexStorage rawVectorShape = polygonShape.PolygonToPathStorage(); + VertexStorage rawVectorShape = polygonShapes.PolygonToPathStorage(); var aabb = this.VisibleMeshes().FirstOrDefault().GetAxisAlignedBoundingBox(); var xScale = aabb.XSize / image.Width; @@ -295,7 +313,8 @@ namespace MatterHackers.MatterControl.DesignTools reporter.Report(progressStatus); }, SourceImage, - new AlphaFunction()); + new AlphaFunction(), + (int)(MinSurfaceArea * 1000)); break; case AnalysisTypes.Colors: @@ -308,7 +327,8 @@ namespace MatterHackers.MatterControl.DesignTools reporter.Report(progressStatus); }, alphaImage, - new AlphaFunction()); + new AlphaFunction(), + (int)(Math.Pow(MinSurfaceArea * 1000, 2))); break; } @@ -334,6 +354,7 @@ namespace MatterHackers.MatterControl.DesignTools public void UpdateControls(PublicPropertyChange change) { change.SetRowVisible(nameof(Histogram), () => AnalysisType != AnalysisTypes.Transparency); + change.SetRowVisible(nameof(MinSurfaceArea), () => AnalysisType != AnalysisTypes.Transparency); change.SetRowVisible(nameof(TransparencyMessage), () => AnalysisType == AnalysisTypes.Transparency); } } diff --git a/MatterControlLib/PartPreviewWindow/SelectedObjectPanel.cs b/MatterControlLib/PartPreviewWindow/SelectedObjectPanel.cs index 66d87e5ff..046c2ccb6 100644 --- a/MatterControlLib/PartPreviewWindow/SelectedObjectPanel.cs +++ b/MatterControlLib/PartPreviewWindow/SelectedObjectPanel.cs @@ -305,6 +305,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow if (selectedItem is ComponentObject3D componentObject && componentObject.Finalized) { + var context = new PPEContext(); PublicPropertyEditor.AddUnlockLinkIfRequired(selectedItem, editorPanel, theme); foreach (var selector in componentObject.SurfacedEditors) { @@ -356,8 +357,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } else if (JsonPathContext.ReflectionValueSystem.LastMemberValue is ReflectionTarget reflectionTarget) { - var context = new PPEContext(); - if (reflectionTarget.Source is IObject3D editedChild) { context.item = editedChild; @@ -374,6 +373,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { editorPanel.AddChild(editor); } + + // Init with custom 'UpdateControls' hooks + (context.item as IPropertyGridModifier)?.UpdateControls(new PublicPropertyChange(context, "Update_Button")); } } } From 8f8254e2ffba611ef7f3b74ae60b4b6e1153d518 Mon Sep 17 00:00:00 2001 From: Lars Brubaker Date: Fri, 20 Aug 2021 16:55:29 -0700 Subject: [PATCH 4/4] Made image converter select good filter Fixed bug with bed not showing top texture --- .../Operations/Image/ImageToPathObject3D_2.cs | 72 +++++++++++++++++-- .../Operations/Object3DExtensions.cs | 27 +++++++ .../SceneViewer/FloorDrawable.cs | 4 +- Submodules/MatterSlice | 2 +- Submodules/agg-sharp | 2 +- 5 files changed, 96 insertions(+), 11 deletions(-) diff --git a/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D_2.cs b/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D_2.cs index a1f398f7b..d38eaa918 100644 --- a/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D_2.cs +++ b/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D_2.cs @@ -44,6 +44,7 @@ using MatterHackers.Localizations; using MatterHackers.MarchingSquares; using MatterHackers.MatterControl.DesignTools.Operations; using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.VectorMath; using Newtonsoft.Json; using Polygon = System.Collections.Generic.List; using Polygons = System.Collections.Generic.List>; @@ -185,7 +186,7 @@ namespace MatterHackers.MatterControl.DesignTools this.FlattenToPathObject(undoBuffer); } - public void GenerateMarchingSquaresAndLines(Action progressReporter, ImageBuffer image, IThresholdFunction thresholdFunction, int minimumSurfaceArea) + public void GenerateMarchingSquaresAndLines(Action progressReporter, ImageBuffer image, IThresholdFunction thresholdFunction) { if (image != null) { @@ -204,9 +205,11 @@ namespace MatterHackers.MatterControl.DesignTools int pixelsToIntPointsScale = 1000; var lineLoops = marchingSquaresData.CreateLineLoops(pixelsToIntPointsScale); - if (minimumSurfaceArea > 0) + if (MinSurfaceArea > 0) { - for(int i=lineLoops.Count - 1; i >=0; i--) + var minimumSurfaceArea = Math.Pow(MinSurfaceArea * 1000, 2); + + for (int i=lineLoops.Count - 1; i >=0; i--) { var area = Math.Abs(Clipper.Area(lineLoops[i])); if (area < minimumSurfaceArea) @@ -260,12 +263,67 @@ namespace MatterHackers.MatterControl.DesignTools } } + private bool ColorDetected(ImageBuffer sourceImage, out double hueDetected) + { + byte[] sourceBuffer = sourceImage.GetBuffer(); + var min = new Vector3(double.MaxValue, double.MaxValue, double.MaxValue); + var max = new Vector3(double.MinValue, double.MinValue, double.MinValue); + + for(int y = 0; y < sourceImage.Height; y++) + { + int imageOffset = sourceImage.GetBufferOffsetY(y); + for (int x = 0; x < sourceImage.Width; x++) + { + int offset = imageOffset + x * 4; + var b = sourceBuffer[offset + 0]; + var g = sourceBuffer[offset + 1]; + var r = sourceBuffer[offset + 2]; + + var color = new ColorF(r / 255.0, g / 255.0, b / 255.0); + color.GetHSL(out double hue, out double saturation, out double lightness); + + min = Vector3.ComponentMin(min, new Vector3(hue, saturation, lightness)); + max = Vector3.ComponentMax(max, new Vector3(hue, saturation, lightness)); + + if (saturation > .4 && lightness > .1 && lightness < .9) + { + hueDetected = hue; + return true; + } + } + } + + hueDetected = 0; + return false; + } + public override async void OnInvalidate(InvalidateArgs invalidateArgs) { if (invalidateArgs.InvalidateType.HasFlag(InvalidateType.Image) && invalidateArgs.Source != this && !RebuildLocked) { + // try to pick the best processing mode + if (SourceImage.HasTransparency) + { + AnalysisType = AnalysisTypes.Transparency; + Histogram.RangeStart = 0; + Histogram.RangeEnd = .9; + } + else if (ColorDetected(SourceImage, out double hue)) + { + AnalysisType = AnalysisTypes.Colors; + Histogram.RangeStart = Math.Max(0, hue - .2); + Histogram.RangeEnd = Math.Min(1, hue + .2); + } + else + { + AnalysisType = AnalysisTypes.Intensity; + Histogram.RangeStart = 0; + Histogram.RangeEnd = .9; + } + + if (AnalysisType != AnalysisTypes.Transparency) { Histogram.BuildHistogramFromImage(SourceImage, AnalysisType); @@ -277,6 +335,8 @@ namespace MatterHackers.MatterControl.DesignTools Image?.CopyFrom(SourceImage); } await Rebuild(); + + this.ReloadEditorPannel(); } else if ((invalidateArgs.InvalidateType.HasFlag(InvalidateType.Properties) && invalidateArgs.Source == this)) { @@ -313,8 +373,7 @@ namespace MatterHackers.MatterControl.DesignTools reporter.Report(progressStatus); }, SourceImage, - new AlphaFunction(), - (int)(MinSurfaceArea * 1000)); + new AlphaFunction()); break; case AnalysisTypes.Colors: @@ -327,8 +386,7 @@ namespace MatterHackers.MatterControl.DesignTools reporter.Report(progressStatus); }, alphaImage, - new AlphaFunction(), - (int)(Math.Pow(MinSurfaceArea * 1000, 2))); + new AlphaFunction()); break; } diff --git a/MatterControlLib/DesignTools/Operations/Object3DExtensions.cs b/MatterControlLib/DesignTools/Operations/Object3DExtensions.cs index c938083da..a1b45d2e4 100644 --- a/MatterControlLib/DesignTools/Operations/Object3DExtensions.cs +++ b/MatterControlLib/DesignTools/Operations/Object3DExtensions.cs @@ -99,6 +99,33 @@ namespace MatterHackers.MatterControl.DesignTools.Operations return null; } + public static InteractiveScene ContainingScene(this IObject3D object3D) + { + foreach (var workspace in ApplicationController.Instance.Workspaces) + { + if (workspace.SceneContext.Scene.Descendants().Contains(object3D)) + { + return workspace.SceneContext.Scene; + } + } + + return null; + } + + public static void ReloadEditorPannel(this IObject3D object3D) + { + // de-select and select this object + var scene = object3D.ContainingScene(); + if (scene != null + && (object3D.Parents().Contains(scene.SelectedItem) + || object3D == scene.SelectedItem)) + { + var selection = scene.SelectedItem; + scene.SelectedItem = null; + scene.SelectedItem = selection; + } + } + public static int EstimatedMemory(this IObject3D object3D) { return 0; diff --git a/MatterControlLib/PartPreviewWindow/SceneViewer/FloorDrawable.cs b/MatterControlLib/PartPreviewWindow/SceneViewer/FloorDrawable.cs index 9d3a00102..356548bbb 100644 --- a/MatterControlLib/PartPreviewWindow/SceneViewer/FloorDrawable.cs +++ b/MatterControlLib/PartPreviewWindow/SceneViewer/FloorDrawable.cs @@ -101,11 +101,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow GLHelper.Render( sceneContext.Mesh, - theme.UnderBedColor, + theme.UnderBedColor.WithAlpha(32), RenderTypes.Shaded, world.ModelviewMatrix, blendTexture: !this.LookingDownOnBed, - forceCullBackFaces: true); + forceCullBackFaces: false); if (sceneContext.PrinterShape != null) { diff --git a/Submodules/MatterSlice b/Submodules/MatterSlice index adb494612..2ae23e64a 160000 --- a/Submodules/MatterSlice +++ b/Submodules/MatterSlice @@ -1 +1 @@ -Subproject commit adb494612051827f20328a624bee101559d6ace5 +Subproject commit 2ae23e64a38e0d13da4ba6c9e8803ee07d8daf05 diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index 0e6c40749..cb957e18f 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit 0e6c407494ab8a587e950ed5e544c0404b1edd71 +Subproject commit cb957e18fa363d13c6b36e02b603a5bf687bc2f5