diff --git a/AboutPage/AboutWidget.cs b/AboutPage/AboutWidget.cs index 9db97b695..0cba53487 100644 --- a/AboutPage/AboutWidget.cs +++ b/AboutPage/AboutWidget.cs @@ -93,6 +93,9 @@ namespace MatterHackers.MatterControl public static void DeleteCacheData(int daysOldToDelete) { + // TODO: Enable once the cache mechanism is scene graph aware + return; + if (LibraryProviderSQLite.PreloadingCalibrationFiles) { return; diff --git a/ApplicationView/MenuRow/MenuOptionFile.cs b/ApplicationView/MenuRow/MenuOptionFile.cs index f997e64f4..9a2b12d9b 100644 --- a/ApplicationView/MenuRow/MenuOptionFile.cs +++ b/ApplicationView/MenuRow/MenuOptionFile.cs @@ -88,38 +88,41 @@ namespace MatterHackers.MatterControl private void importFile_Click() { - FileDialog.OpenFileDialog( - new OpenFileDialogParams(ApplicationSettings.OpenPrintableFileParams) - { - MultiSelect = true, - ActionButtonLabel = "Add to Queue", - Title = "MatterControl: Select A File" - }, - (openParams) => - { - if (openParams.FileNames != null) + UiThread.RunOnIdle(() => + { + FileDialog.OpenFileDialog( + new OpenFileDialogParams(ApplicationSettings.OpenPrintableFileParams) { - foreach (string loadedFileName in openParams.FileNames) + MultiSelect = true, + ActionButtonLabel = "Add to Queue", + Title = "MatterControl: Select A File" + }, + (openParams) => + { + if (openParams.FileNames != null) { - if (Path.GetExtension(loadedFileName).ToUpper() == ".ZIP") + foreach (string loadedFileName in openParams.FileNames) { - ProjectFileHandler project = new ProjectFileHandler(null); - List partFiles = project.ImportFromProjectArchive(loadedFileName); - if (partFiles != null) - { - foreach (PrintItem part in partFiles) - { - QueueData.Instance.AddItem(new PrintItemWrapper(new PrintItem(part.Name, part.FileLocation))); - } - } - } - else - { - QueueData.Instance.AddItem(new PrintItemWrapper(new PrintItem(Path.GetFileNameWithoutExtension(loadedFileName), Path.GetFullPath(loadedFileName)))); + if (Path.GetExtension(loadedFileName).ToUpper() == ".ZIP") + { + List partFiles = ProjectFileHandler.ImportFromProjectArchive(loadedFileName); + if (partFiles != null) + { + foreach (PrintItem part in partFiles) + { + QueueData.Instance.AddItem(new PrintItemWrapper(new PrintItem(part.Name, part.FileLocation))); + } + } + } + else + { + QueueData.Instance.AddItem(new PrintItemWrapper(new PrintItem(Path.GetFileNameWithoutExtension(loadedFileName), Path.GetFullPath(loadedFileName)))); + } } } - } - }); + }); + }); } + } -} \ No newline at end of file +} diff --git a/ApplicationView/WidescreenPanel.cs b/ApplicationView/WidescreenPanel.cs index f4187cf66..ef1d4ac1d 100644 --- a/ApplicationView/WidescreenPanel.cs +++ b/ApplicationView/WidescreenPanel.cs @@ -68,7 +68,6 @@ namespace MatterHackers.MatterControl BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; Padding = new BorderDouble(4); - PrinterConnectionAndCommunication.Instance.ActivePrintItemChanged.RegisterEvent(onActivePrintItemChanged, ref unregisterEvents); ApplicationController.Instance.AdvancedControlsPanelReloading.RegisterEvent((s, e) => UiThread.RunOnIdle(ReloadAdvancedControlsPanel), ref unregisterEvents); } @@ -88,14 +87,6 @@ namespace MatterHackers.MatterControl base.OnClosed(e); } - private void onActivePrintItemChanged(object sender, EventArgs e) - { - if (this.VisiblePanelCount > 1) - { - UiThread.RunOnIdle(LoadColumnTwo); - } - } - private CompactSlidePanel compactSlidePanel; private void LoadCompactView() @@ -115,7 +106,7 @@ namespace MatterHackers.MatterControl ColumnTwo.CloseAllChildren(); PopOutManager.SaveIfClosed = true; - PartPreviewContent partViewContent = new PartPreviewContent(PrinterConnectionAndCommunication.Instance.ActivePrintItem, View3DWidget.WindowMode.Embeded, View3DWidget.AutoRotate.Enabled); + PartPreviewContent partViewContent = new PartPreviewContent(PrinterConnectionAndCommunication.Instance.ActivePrintItem, View3DWidget.WindowMode.Embeded, View3DWidget.AutoRotate.Disabled); partViewContent.AnchorAll(); ColumnTwo.AddChild(partViewContent); diff --git a/BrailleBuilder/BrailleBuilder.cs b/BrailleBuilder/BrailleBuilder.cs deleted file mode 100644 index a3aa9c18c..000000000 --- a/BrailleBuilder/BrailleBuilder.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright (c) 2014, Lars Brubaker -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 MatterHackers.Agg.UI; -using MatterHackers.Localizations; -using MatterHackers.MatterControl.CreatorPlugins; -using MatterHackers.MatterControl.PluginSystem; -using System; - -namespace MatterHackers.MatterControl.Plugins.BrailleBuilder -{ -#if false - public class BrailleBuilderPlugin : MatterControlPlugin - { - public BrailleBuilderPlugin() - { - } - - private GuiWidget mainApplication; - - public override void Initialize(GuiWidget application) - { - CreatorInformation information = new CreatorInformation(LaunchNewBrailleBuilder, "BB_32x32.png", "Braille Builder".Localize()); - RegisteredCreators.Instance.RegisterLaunchFunction(information); - mainApplication = application; - - if (false) - { - UiThread.RunOnIdle(() => - { - LaunchNewBrailleBuilder(null, null); - }, .5); - } - } - - public override string GetPluginInfoJSon() - { - return "{" + - "\"Name\": \"Braille Builder\"," + - "\"UUID\": \"9F1152BA-2D9E-44FC-93FD-B55FC6FD8D9E\"," + - "\"About\": \"A Creator that allows you to type in text and have it turned into a printable Braille extrusions.\"," + - "\"Developer\": \"MatterHackers, Inc.\"," + - "\"URL\": \"https://www.matterhackers.com\"" + - "}"; - } - - public void LaunchNewBrailleBuilder(object sender, EventArgs e) - { - BrailleBuilderMainWindow mainWindow = new BrailleBuilderMainWindow(); - } - } -#endif -} \ No newline at end of file diff --git a/BrailleBuilder/BrailleBuilder.csproj b/BrailleBuilder/BrailleBuilder.csproj deleted file mode 100644 index dfb391337..000000000 --- a/BrailleBuilder/BrailleBuilder.csproj +++ /dev/null @@ -1,226 +0,0 @@ - - - - Release - AnyCPU - 8.0.50727 - 2.0 - {70FBB82C-558D-4B5F-BE75-A922D392E650} - Library - Properties - MatterHackers.Plugins.BrailBuilder - BrailBuilder - - - - - 2.0 - v4.6.1 - - - - True - full - False - ..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - True - x86 - false - - - pdbonly - True - ..\bin\Release\ - TRACE - prompt - 4 - True - x86 - false - - - false - - - bin\Release64\ - TRACE - true - true - pdbonly - x64 - ..\..\MatterControl\bin\Release\BrailBuilder.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - false - false - - - true - bin\Debug64\ - DEBUG;TRACE - true - full - x86 - prompt - false - false - - - true - bin\x64\Debug\ - DEBUG;TRACE - true - full - x64 - prompt - false - false - false - - - bin\x64\Release\ - TRACE - true - true - pdbonly - x64 - prompt - false - false - false - - - bin\x64\Release64\ - TRACE - true - true - pdbonly - x64 - ..\..\MatterControl\bin\Release\BrailBuilder.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - false - - - true - bin\x64\Debug64\ - DEBUG;TRACE - true - full - x64 - prompt - false - false - false - - - - False - ..\Submodules\agg-sharp\PlatformWin32\OpenTK.dll - - - - - - - - - - - - - {657DBC6D-C3EA-4398-A3FA-DDB73C14F71B} - Agg - - - {9B062971-A88E-4A3D-B3C9-12B78D15FA66} - clipper_library - - - {94838988-523C-4B11-AD82-8B9B76F23A31} - DataConverters2D - - - {04667764-DC7B-4B95-AEF6-B4E6C87A54E9} - DataConverters3D - - - {A737BC76-165B-46C6-82B7-8871C7C92942} - MeshViewer - - - {74F6BB6C-9D02-4512-A59A-21940E35C532} - Gui - - - {036BCCBA-52D8-457C-84AE-8821F209FE4A} - ImageProcessing - - - {DF6845CD-64C6-4263-8357-DA8066855739} - MarchingSquares - - - {C958F745-156E-4BDC-A24A-3721C7BE7B8A} - OpenGlGui - - - {3E4AABA8-D85F-4922-88C6-5C1B2D2308FB} - PlatformAbstract - - - {86F6AAF2-9B50-40B8-A427-1897D76471C5} - PolygonMesh - - - {1E01ABE0-B494-4FE4-B0D6-540133286887} - RayTracer - - - {545B6912-77FF-4B34-BA76-6C3D6A32BE6A} - RenderOpenGl - - - {D3E41B4E-BFBB-44CA-94C8-95C00F754FDD} - VectorMath - - - {0B8D6F56-BD7F-4426-B858-D9292B084656} - MatterControl - - - {865172A0-A1A9-49C2-9386-F2FDB4E141B7} - MatterControlPluginSystem - - - {C46CA728-DD2F-4DD1-971A-AAA89D9DFF95} - MatterSlice - - - - - - - - - - - - - - \ No newline at end of file diff --git a/BrailleBuilder/View3DBrailleBuilder.cs b/BrailleBuilder/View3DBrailleBuilder.cs deleted file mode 100644 index 73bf74bc0..000000000 --- a/BrailleBuilder/View3DBrailleBuilder.cs +++ /dev/null @@ -1,947 +0,0 @@ -/* -Copyright (c) 2014, Lars Brubaker -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 ClipperLib; -using MatterHackers.Agg; -using MatterHackers.Agg.Font; -using MatterHackers.Agg.ImageProcessing; -using MatterHackers.Agg.PlatformAbstract; -using MatterHackers.Agg.UI; -using MatterHackers.Agg.VertexSource; -using MatterHackers.DataConverters2D; -using MatterHackers.DataConverters3D; -using MatterHackers.Localizations; -using MatterHackers.MatterControl.DataStorage; -using MatterHackers.MatterControl.PartPreviewWindow; -using MatterHackers.MatterControl.PrintQueue; -using MatterHackers.MatterControl.SlicerConfiguration; -using MatterHackers.MeshVisualizer; -using MatterHackers.PolygonMesh; -using MatterHackers.PolygonMesh.Csg; -using MatterHackers.PolygonMesh.Processors; -using MatterHackers.RayTracer; -using MatterHackers.RayTracer.Traceable; -using MatterHackers.RenderOpenGl; -using MatterHackers.VectorMath; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace MatterHackers.MatterControl.Plugins.BrailleBuilder -{ - public class View3DBrailleBuilder : PartPreview3DWidget - { - private MHTextEditWidget textToAddWidget; - private SolidSlider sizeScrollBar; - private SolidSlider heightScrollBar; - private CheckBox includeText; - private CheckBox useGrade2; - - private double lastHeightValue = 1; - private double lastSizeValue = 1; - private const double unscaledBaseHeight = 7; - private const double unscaledLetterHeight = 3; - - private ProgressControl processingProgressControl; - private FlowLayoutWidget editPlateButtonsContainer; - - private Button saveButton; - private Button saveAndExitButton; - private Button closeButton; - private String word; - - private List asyncMeshGroups = new List(); - private List asyncMeshGroupTransforms = new List(); - private List asyncPlatingDatas = new List(); - - private List MeshGroupExtraData; - - public Matrix4X4 SelectedMeshTransform - { - get { return meshViewerWidget.SelectedMeshGroupTransform; } - set { meshViewerWidget.SelectedMeshGroupTransform = value; } - } - - public MeshGroup SelectedMeshGroup - { - get - { - return meshViewerWidget.SelectedMeshGroup; - } - } - - public int SelectedMeshGroupIndex - { - get - { - return meshViewerWidget.SelectedMeshGroupIndex; - } - set - { - meshViewerWidget.SelectedMeshGroupIndex = value; - } - } - - public List MeshGroups - { - get - { - return meshViewerWidget.MeshGroups; - } - } - - public List MeshGroupTransforms - { - get { return meshViewerWidget.MeshGroupTransforms; } - } - - internal struct MeshSelectInfo - { - internal Vector3 planeDownHitPos; - internal Vector3 lastMoveDelta; - } - - private TypeFace brailTypeFace; - private TypeFace monoSpacedTypeFace; - - public View3DBrailleBuilder(Vector3 viewerVolume, Vector2 bedCenter, BedShape bedShape) - { - monoSpacedTypeFace = ApplicationController.MonoSpacedTypeFace; - - brailTypeFace = TypeFace.LoadFrom(StaticData.Instance.ReadAllText(Path.Combine("Fonts", "Braille.svg"))); - - MeshGroupExtraData = new List(); - - FlowLayoutWidget mainContainerTopToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom); - mainContainerTopToBottom.HAnchor = Agg.UI.HAnchor.Max_FitToChildren_ParentWidth; - mainContainerTopToBottom.VAnchor = Agg.UI.VAnchor.Max_FitToChildren_ParentHeight; - - FlowLayoutWidget centerPartPreviewAndControls = new FlowLayoutWidget(FlowDirection.LeftToRight); - centerPartPreviewAndControls.AnchorAll(); - - GuiWidget viewArea = new GuiWidget(); - viewArea.AnchorAll(); - { - meshViewerWidget = new MeshViewerWidget(viewerVolume, bedCenter, bedShape); - meshViewerWidget.AllowBedRenderingWhenEmpty = true; - meshViewerWidget.AnchorAll(); - } - viewArea.AddChild(meshViewerWidget); - - centerPartPreviewAndControls.AddChild(viewArea); - mainContainerTopToBottom.AddChild(centerPartPreviewAndControls); - - FlowLayoutWidget buttonBottomPanel = new FlowLayoutWidget(FlowDirection.LeftToRight); - buttonBottomPanel.HAnchor = HAnchor.ParentLeftRight; - buttonBottomPanel.Padding = new BorderDouble(3, 3); - buttonBottomPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - - buttonRightPanel = CreateRightButtonPanel(viewerVolume.y); - - // add in the plater tools - { - FlowLayoutWidget editToolBar = new FlowLayoutWidget(); - - processingProgressControl = new ProgressControl("Finding Parts:".Localize(), ActiveTheme.Instance.PrimaryTextColor, ActiveTheme.Instance.PrimaryAccentColor); - processingProgressControl.VAnchor = Agg.UI.VAnchor.ParentCenter; - editToolBar.AddChild(processingProgressControl); - editToolBar.VAnchor |= Agg.UI.VAnchor.ParentCenter; - - editPlateButtonsContainer = new FlowLayoutWidget(); - - textToAddWidget = new MHTextEditWidget("", pixelWidth: 300, messageWhenEmptyAndNotSelected: "Enter Text Here".Localize()); - textToAddWidget.VAnchor = VAnchor.ParentCenter; - textToAddWidget.Margin = new BorderDouble(5); - editPlateButtonsContainer.AddChild(textToAddWidget); - textToAddWidget.ActualTextEditWidget.EnterPressed += (object sender, KeyEventArgs keyEvent) => - { - InsertTextNow(textToAddWidget.Text); - }; - - Button insertTextButton = textImageButtonFactory.Generate("Insert".Localize()); - editPlateButtonsContainer.AddChild(insertTextButton); - insertTextButton.Click += (sender, e) => - { - InsertTextNow(textToAddWidget.Text); - }; - - editToolBar.AddChild(editPlateButtonsContainer); - buttonBottomPanel.AddChild(editToolBar); - } - - GuiWidget buttonRightPanelHolder = new GuiWidget() - { - HAnchor = HAnchor.FitToChildren, - VAnchor = VAnchor.ParentBottomTop - }; - centerPartPreviewAndControls.AddChild(buttonRightPanelHolder); - buttonRightPanelHolder.AddChild(buttonRightPanel); - - viewControls3D = new ViewControls3D(meshViewerWidget); - - viewControls3D.ResetView += (sender, e) => - { - meshViewerWidget.ResetView(); - }; - - buttonRightPanelDisabledCover = new GuiWidget() - { - HAnchor = HAnchor.ParentLeftRight, - VAnchor = VAnchor.ParentBottomTop - }; - buttonRightPanelDisabledCover.BackgroundColor = new RGBA_Bytes(ActiveTheme.Instance.PrimaryBackgroundColor, 150); - buttonRightPanelHolder.AddChild(buttonRightPanelDisabledCover); - LockEditControls(); - - GuiWidget leftRightSpacer = new GuiWidget(); - leftRightSpacer.HAnchor = HAnchor.ParentLeftRight; - buttonBottomPanel.AddChild(leftRightSpacer); - - closeButton = textImageButtonFactory.Generate("Close".Localize()); - buttonBottomPanel.AddChild(closeButton); - - mainContainerTopToBottom.AddChild(buttonBottomPanel); - - this.AddChild(mainContainerTopToBottom); - this.AnchorAll(); - - meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation; - - AddChild(viewControls3D); - - // set the view to be a good angle and distance - meshViewerWidget.ResetView(); - - AddHandlers(); - UnlockEditControls(); - // but make sure we can't use the right panel yet - buttonRightPanelDisabledCover.Visible = true; - - //meshViewerWidget.RenderType = RenderTypes.Outlines; - viewControls3D.PartSelectVisible = false; - meshViewerWidget.ResetView(); - } - - private async void InsertTextNow(string text) - { - if (text.Length > 0) - { - this.word = text; - if (useGrade2.Checked) - { - text = BrailleGrade2.ConvertString(text); - } - ResetWordLayoutSettings(); - processingProgressControl.ProcessType = "Inserting Text".Localize(); - processingProgressControl.Visible = true; - processingProgressControl.PercentComplete = 0; - LockEditControls(); - - await Task.Run(() => InsertTextDoWork(text,this.word));//replace with this.word when not testing conversions - - PullMeshDataFromAsynchLists(); - SelectedMeshGroupIndex = MeshGroups.Count - 1; - RebuildBase(); - CenterTextOnScreen(MeshGroups, MeshGroupTransforms); - - UnlockEditControls(); - saveButton.Visible = true; - saveAndExitButton.Visible = true; - SelectedMeshGroupIndex = MeshGroups.Count - 1; - } - } - - private void SetWordPositions(List meshesList, List meshTransforms, List platingDataList) - { - if (meshesList.Count > 0) - { - for (int meshIndex = 0; meshIndex < meshesList.Count - 1; meshIndex++) - { - Vector3 startPosition = Vector3.Transform(Vector3.Zero, meshTransforms[meshIndex]); - - meshTransforms[meshIndex] *= Matrix4X4.CreateTranslation(-startPosition); - double newX = platingDataList[meshIndex].spacing.x * lastSizeValue; - double newY = platingDataList[meshIndex].spacing.y * lastSizeValue; - meshTransforms[meshIndex] *= Matrix4X4.CreateTranslation(new Vector3(newX, newY, startPosition.z) + new Vector3(MeshViewerWidget.BedCenter)); - } - - CenterTextOnScreen(meshesList, meshTransforms); - } - } - - private void ResetWordLayoutSettings() - { - sizeScrollBar.Value = 1; - heightScrollBar.Value = 1; - lastHeightValue = 1; - lastSizeValue = 1; - } - - private bool FindMeshGroupHitPosition(Vector2 screenPosition, out int meshHitIndex) - { - meshHitIndex = 0; - if (MeshGroupExtraData.Count == 0 || MeshGroupExtraData[0].meshTraceableData == null) - { - return false; - } - - List mesheTraceables = new List(); - for (int i = 0; i < MeshGroupExtraData.Count; i++) - { - foreach (IPrimitive traceData in MeshGroupExtraData[i].meshTraceableData) - { - mesheTraceables.Add(new Transform(traceData, MeshGroupTransforms[i])); - } - } - IPrimitive allObjects = BoundingVolumeHierarchy.CreateNewHierachy(mesheTraceables); - - Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, screenPosition); - Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayFromScreen(meshViewerWidgetScreenPosition); - IntersectInfo info = allObjects.GetClosestIntersection(ray); - if (info != null) - { - meshSelectInfo.planeDownHitPos = info.hitPosition; - meshSelectInfo.lastMoveDelta = new Vector3(); - - for (int i = 0; i < MeshGroupExtraData.Count; i++) - { - List insideBounds = new List(); - foreach (IPrimitive traceData in MeshGroupExtraData[i].meshTraceableData) - { - traceData.GetContained(insideBounds, info.closestHitObject.GetAxisAlignedBoundingBox()); - } - if (insideBounds.Contains(info.closestHitObject)) - { - meshHitIndex = i; - return true; - } - } - } - - return false; - } - - private Matrix4X4 transformOnMouseDown = Matrix4X4.Identity; - private MeshSelectInfo meshSelectInfo; - - private bool firstDraw = true; - - public override void OnDraw(Graphics2D graphics2D) - { - if (firstDraw) - { - if (!UserSettings.Instance.IsTouchScreen) - { - textToAddWidget.Focus(); - } - - //textToAddWidget.Text = "Test Text"; - firstDraw = false; - } - - base.OnDraw(graphics2D); - } - - private void InsertTextDoWork(string brailleText, string wordText) - { - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - - asyncMeshGroups.Clear(); - asyncMeshGroupTransforms.Clear(); - asyncPlatingDatas.Clear(); - - TypeFacePrinter brailPrinter = new TypeFacePrinter(brailleText, new StyledTypeFace(brailTypeFace, 12)); - - int firstNewCharacter = 0; - StyledTypeFace boldStyled = new StyledTypeFace(monoSpacedTypeFace, 12); - - if (includeText.Checked) - { - TypeFacePrinter normalPrinter = new TypeFacePrinter(wordText, boldStyled); - Vector2 normalSize = normalPrinter.GetSize(); - AddCharacterMeshes(wordText, normalPrinter); - - firstNewCharacter = asyncPlatingDatas.Count; - } - - AddCharacterMeshes(brailleText, brailPrinter); - Vector2 brailSize = brailPrinter.GetSize(); - - for (int i = 0; i < firstNewCharacter; i++) - { - asyncPlatingDatas[i].spacing = asyncPlatingDatas[i].spacing + new Vector2(0, boldStyled.CapHeightInPixels * 1.5); - } - - CreateBase(asyncMeshGroups, asyncMeshGroupTransforms, asyncPlatingDatas); - - SetWordPositions(asyncMeshGroups, asyncMeshGroupTransforms, asyncPlatingDatas); - SetWordSize(asyncMeshGroups, asyncMeshGroupTransforms); - SetWordHeight(asyncMeshGroups, asyncMeshGroupTransforms); - - CenterTextOnScreen(asyncMeshGroups, asyncMeshGroupTransforms); - - processingProgressControl.PercentComplete = 95; - } - - private void AddCharacterMeshes(string currentText, TypeFacePrinter printer) - { - int newIndex = asyncMeshGroups.Count; - StyledTypeFace typeFace = printer.TypeFaceStyle; - - for (int i = 0; i < currentText.Length; i++) - { - string letter = currentText[i].ToString(); - TypeFacePrinter letterPrinter = new TypeFacePrinter(letter, typeFace); - - if (CharacterHasMesh(letterPrinter, letter)) - { -#if true - Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2); -#else - Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2); - // this is the code to make rounded tops - // convert the letterPrinter to clipper polygons - List> insetPoly = VertexSourceToPolygon.CreatePolygons(letterPrinter); - // inset them - ClipperOffset clipper = new ClipperOffset(); - clipper.AddPaths(insetPoly, JoinType.jtMiter, EndType.etClosedPolygon); - List> solution = new List>(); - clipper.Execute(solution, 5.0); - // convert them back into a vertex source - // merge both the inset and original vertex sources together - // convert the new vertex source into a mesh (triangulate them) - // offset the inner loop in z - // create the polygons from the inner loop to a center point so that there is the rest of an approximation of the bubble - // make the mesh for the bottom - // add the top and bottom together - // done -#endif - - asyncMeshGroups.Add(new MeshGroup(textMesh)); - - PlatingMeshGroupData newMeshInfo = new PlatingMeshGroupData(); - - newMeshInfo.spacing = printer.GetOffsetLeftOfCharacterIndex(i); - asyncPlatingDatas.Add(newMeshInfo); - asyncMeshGroupTransforms.Add(Matrix4X4.Identity); - - PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, newIndex, null); - asyncMeshGroupTransforms[newIndex] *= Matrix4X4.CreateTranslation(new Vector3(0, 0, unscaledLetterHeight / 2)); - - newIndex++; - } - - processingProgressControl.PercentComplete = ((i + 1) * 95 / currentText.Length); - } - } - - private void CreateBase(List meshesList, List meshTransforms, List platingDataList) - { - if (meshesList.Count > 0) - { - AxisAlignedBoundingBox bounds = meshesList[0].GetAxisAlignedBoundingBox(meshTransforms[0]); - for (int i = 1; i < meshesList.Count; i++) - { - bounds = AxisAlignedBoundingBox.Union(bounds, meshesList[i].GetAxisAlignedBoundingBox(meshTransforms[i])); - } - - double roundingScale = 20; - RectangleDouble baseRect = new RectangleDouble(bounds.minXYZ.x, bounds.minXYZ.y, bounds.maxXYZ.x, bounds.maxXYZ.y); - baseRect.Inflate(2); - baseRect *= roundingScale; - RoundedRect baseRoundedRect = new RoundedRect(baseRect, 1 * roundingScale); - - Mesh baseMeshResult = VertexSourceToMesh.Extrude(baseRoundedRect, unscaledBaseHeight / 2 * roundingScale * sizeScrollBar.Value * heightScrollBar.Value); - - baseMeshResult.Transform(Matrix4X4.CreateScale(1 / roundingScale)); - - meshesList.Add(new MeshGroup(baseMeshResult)); - platingDataList.Add(new PlatingMeshGroupData()); - meshTransforms.Add(Matrix4X4.CreateTranslation(0, 0, 0)); - PlatingHelper.CreateITraceableForMeshGroup(platingDataList, meshesList, meshesList.Count - 1, null); - } - } - - private void PushMeshGroupDataToAsynchLists(bool copyTraceInfo) - { - asyncMeshGroups.Clear(); - asyncMeshGroupTransforms.Clear(); - for (int meshGroupIndex = 0; meshGroupIndex < MeshGroups.Count; meshGroupIndex++) - { - MeshGroup meshGroup = MeshGroups[meshGroupIndex]; - MeshGroup newMeshGroup = new MeshGroup(); - for (int meshIndex = 0; meshIndex < meshGroup.Meshes.Count; meshIndex++) - { - Mesh mesh = meshGroup.Meshes[meshIndex]; - mesh.CleanAndMergMesh(); - newMeshGroup.Meshes.Add(Mesh.Copy(mesh)); - asyncMeshGroupTransforms.Add(MeshGroupTransforms[meshGroupIndex]); - } - asyncMeshGroups.Add(newMeshGroup); - } - asyncPlatingDatas.Clear(); - - for (int meshGroupIndex = 0; meshGroupIndex < MeshGroupExtraData.Count; meshGroupIndex++) - { - PlatingMeshGroupData meshData = new PlatingMeshGroupData(); - MeshGroup meshGroup = MeshGroups[meshGroupIndex]; - for (int meshIndex = 0; meshIndex < meshGroup.Meshes.Count; meshIndex++) - { - if (copyTraceInfo) - { - meshData.meshTraceableData.AddRange(MeshGroupExtraData[meshGroupIndex].meshTraceableData); - } - } - asyncPlatingDatas.Add(meshData); - } - } - - private void arrangePartsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - UnlockEditControls(); - saveButton.Visible = true; - saveAndExitButton.Visible = true; - viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect; - - PullMeshDataFromAsynchLists(); - } - - private void PullMeshDataFromAsynchLists() - { - MeshGroups.Clear(); - foreach (MeshGroup mesh in asyncMeshGroups) - { - MeshGroups.Add(mesh); - } - MeshGroupTransforms.Clear(); - foreach (Matrix4X4 transform in asyncMeshGroupTransforms) - { - MeshGroupTransforms.Add(transform); - } - MeshGroupExtraData.Clear(); - foreach (PlatingMeshGroupData meshData in asyncPlatingDatas) - { - MeshGroupExtraData.Add(meshData); - } - } - - private void meshViewerWidget_LoadDone(object sender, EventArgs e) - { - UnlockEditControls(); - } - - private void LockEditControls() - { - editPlateButtonsContainer.Visible = false; - buttonRightPanelDisabledCover.Visible = true; - - if (meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None) - { - viewControls3D.ActiveButton = ViewControls3DButtons.Rotate; - } - } - - private void UnlockEditControls() - { - buttonRightPanelDisabledCover.Visible = false; - processingProgressControl.Visible = false; - - editPlateButtonsContainer.Visible = true; - } - - private void DeleteSelectedMesh() - { - // don't ever delete the last mesh - if (MeshGroups.Count > 1) - { - MeshGroups.RemoveAt(SelectedMeshGroupIndex); - MeshGroupExtraData.RemoveAt(SelectedMeshGroupIndex); - MeshGroupTransforms.RemoveAt(SelectedMeshGroupIndex); - SelectedMeshGroupIndex = MeshGroups.Count - 1; - saveButton.Visible = true; - saveAndExitButton.Visible = true; - Invalidate(); - } - } - - private FlowLayoutWidget CreateRightButtonPanel(double buildHeight) - { - FlowLayoutWidget buttonRightPanel = new FlowLayoutWidget(FlowDirection.TopToBottom); - buttonRightPanel.Width = 200; - { - BorderDouble buttonMargin = new BorderDouble(top: 3); - - // put in the word editing menu - { - CheckBox expandWordOptions = ExpandMenuOptionFactory.GenerateCheckBoxButton("Word Edit".Localize(), - View3DWidget.ArrowRight, - View3DWidget.ArrowDown); - expandWordOptions.Margin = new BorderDouble(bottom: 2); - buttonRightPanel.AddChild(expandWordOptions); - - FlowLayoutWidget wordOptionContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); - wordOptionContainer.HAnchor = HAnchor.ParentLeftRight; - wordOptionContainer.Visible = false; - buttonRightPanel.AddChild(wordOptionContainer); - - sizeScrollBar = InsertUiForSlider(wordOptionContainer, "Size:".Localize(), .3, 2); - { - sizeScrollBar.ValueChanged += (sender, e) => - { - SetWordSize(MeshGroups, MeshGroupTransforms); - - //SetWordSpacing(MeshGroups, MeshGroupTransforms, MeshGroupExtraData); - RebuildBase(); - }; - } - - heightScrollBar = InsertUiForSlider(wordOptionContainer, "Height:".Localize(), .05, 1); - { - heightScrollBar.ValueChanged += (sender, e) => - { - SetWordHeight(MeshGroups, MeshGroupTransforms); - RebuildBase(); - }; - } - - // put in the user alpha check box - { - includeText = new CheckBox(new CheckBoxViewText("Include Text".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor)); - includeText.ToolTipText = "Show normal text above the braille".Localize(); - includeText.Checked = false; - includeText.Margin = new BorderDouble(10, 5); - includeText.HAnchor = HAnchor.ParentLeft; - wordOptionContainer.AddChild(includeText); - includeText.CheckedStateChanged += (sender, e) => - { - InsertTextNow(this.word); - }; - } - - // put in the user alpha check box - { - useGrade2 = new CheckBox(new CheckBoxViewText("Use Grade 2".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor)); - useGrade2.ToolTipText = "Experimental support for Braille grade 2 (contractions)".Localize(); - useGrade2.Checked = false; - useGrade2.Margin = new BorderDouble(10, 5); - useGrade2.HAnchor = HAnchor.ParentLeft; - wordOptionContainer.AddChild(useGrade2); - useGrade2.CheckedStateChanged += (sender, e) => - { - InsertTextNow(this.word); - }; - } - - // put in a link to the wikipedia article - { - LinkButtonFactory linkButtonFactory = new LinkButtonFactory(); - linkButtonFactory.fontSize = 10; - linkButtonFactory.textColor = ActiveTheme.Instance.PrimaryTextColor; - - Button moreAboutBrailleLink = linkButtonFactory.Generate("About Braille".Localize()); - moreAboutBrailleLink.Margin = new BorderDouble(10, 5); - moreAboutBrailleLink.HAnchor = HAnchor.ParentLeft; - moreAboutBrailleLink.Click += (sender, e) => - { - UiThread.RunOnIdle(() => - { - MatterControlApplication.Instance.LaunchBrowser("https://en.wikipedia.org/wiki/Braille"); - }); - }; - - wordOptionContainer.AddChild(moreAboutBrailleLink); - } - - expandWordOptions.CheckedStateChanged += (sender, e) => - { - wordOptionContainer.Visible = expandWordOptions.Checked; - }; - - expandWordOptions.Checked = true; - } - - GuiWidget verticalSpacer = new GuiWidget(); - verticalSpacer.VAnchor = VAnchor.ParentBottomTop; - buttonRightPanel.AddChild(verticalSpacer); - - saveButton = WhiteButtonFactory.Generate("Save".Localize(), centerText: true); - saveButton.Visible = false; - saveButton.Cursor = Cursors.Hand; - - saveAndExitButton = WhiteButtonFactory.Generate("Save & Exit".Localize(), centerText: true); - saveAndExitButton.Visible = false; - saveAndExitButton.Cursor = Cursors.Hand; - - //buttonRightPanel.AddChild(saveButton); - buttonRightPanel.AddChild(saveAndExitButton); - } - - buttonRightPanel.Padding = new BorderDouble(6, 6); - buttonRightPanel.Margin = new BorderDouble(0, 1); - buttonRightPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - buttonRightPanel.VAnchor = VAnchor.ParentBottomTop; - - return buttonRightPanel; - } - - private void RebuildBase() - { - // we need to remove the underline - if (MeshGroups.Count > 1) - { - SelectedMeshGroupIndex = MeshGroups.Count - 1; - DeleteSelectedMesh(); - // we need to add the underline - CreateBase(MeshGroups, MeshGroupTransforms, MeshGroupExtraData); - SelectedMeshGroupIndex = MeshGroups.Count - 1; - } - } - - private bool CharacterHasMesh(TypeFacePrinter letterPrinter, string letter) - { - return letterPrinter.LocalBounds.Width > 0 - && letter != " " - && letter != "\n"; - } - - private void CenterTextOnScreen(List meshesList, List meshTransforms) - { - // center in y - if (meshesList.Count > 0) - { - AxisAlignedBoundingBox bounds = meshesList[0].GetAxisAlignedBoundingBox(meshTransforms[0]); - for (int i = 1; i < meshesList.Count; i++) - { - bounds = AxisAlignedBoundingBox.Union(bounds, meshesList[i].GetAxisAlignedBoundingBox(meshTransforms[i])); - } - - Vector3 bedCenter = new Vector3(MeshViewerWidget.BedCenter); - Vector3 centerOffset = bounds.Center - bedCenter; - - for (int meshIndex = 0; meshIndex < meshesList.Count; meshIndex++) - { - meshTransforms[meshIndex] *= Matrix4X4.CreateTranslation(new Vector3(-centerOffset.x, -centerOffset.y, 0)); - } - } - } - - private void SetWordSize(List meshesList, List meshTransforms) - { - if (meshesList.Count > 0) - { - for (int meshIndex = 0; meshIndex < meshesList.Count; meshIndex++) - { - Vector3 startPositionRelCenter = Vector3.Transform(Vector3.Zero, meshTransforms[meshIndex]); - - // take out the last scale - double oldSize = 1.0 / lastSizeValue; - Vector3 unscaledStartPositionRelCenter = startPositionRelCenter * oldSize; - - double newSize = sizeScrollBar.Value; - Vector3 endPositionRelCenter = unscaledStartPositionRelCenter * newSize; - - Vector3 deltaPosition = endPositionRelCenter - startPositionRelCenter; - - // move the part to keep it in the same relative position - meshTransforms[meshIndex] *= Matrix4X4.CreateScale(new Vector3(oldSize, oldSize, oldSize)); - meshTransforms[meshIndex] *= Matrix4X4.CreateScale(new Vector3(newSize, newSize, newSize)); - meshTransforms[meshIndex] *= Matrix4X4.CreateTranslation(deltaPosition); - } - - lastSizeValue = sizeScrollBar.Value; - } - - CenterTextOnScreen(meshesList, meshTransforms); - } - - private void SetWordHeight(List meshesList, List meshTransforms) - { - if (meshesList.Count > 0) - { - for (int meshIndex = 0; meshIndex < meshesList.Count-1; meshIndex++) - { - Vector3 startPosition = Vector3.Transform(Vector3.Zero, meshTransforms[meshIndex]); - - // take out the last scale - double oldHeight = 1.0 / lastHeightValue; - double newHeight = heightScrollBar.Value; - - // move the part to keep it in the same relative position - meshTransforms[meshIndex] *= Matrix4X4.CreateScale(new Vector3(1, 1, oldHeight)); - meshTransforms[meshIndex] *= Matrix4X4.CreateScale(new Vector3(1, 1, newHeight)); - - // if it's not the base - int baseIndex = meshesList.Count-1; - AxisAlignedBoundingBox baseBounds = meshesList[baseIndex].GetAxisAlignedBoundingBox(meshTransforms[baseIndex]); - - meshTransforms[meshIndex] *= Matrix4X4.CreateTranslation(new Vector3(0, 0, baseBounds.ZSize - startPosition.z)); - } - - lastHeightValue = heightScrollBar.Value; - } - } - - private void AddLetterControls(FlowLayoutWidget buttonPanel) - { - textImageButtonFactory.FixedWidth = 44 * GuiWidget.DeviceScale; - - FlowLayoutWidget degreesContainer = new FlowLayoutWidget(FlowDirection.LeftToRight); - degreesContainer.HAnchor = HAnchor.ParentLeftRight; - degreesContainer.Padding = new BorderDouble(5); - - GuiWidget horizontalSpacer = new GuiWidget(); - horizontalSpacer.HAnchor = HAnchor.ParentLeftRight; - - TextWidget degreesLabel = new TextWidget("Degrees:".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); - degreesContainer.AddChild(degreesLabel); - degreesContainer.AddChild(horizontalSpacer); - - MHNumberEdit degreesControl = new MHNumberEdit(45, pixelWidth: 40, allowNegatives: true, increment: 5, minValue: -360, maxValue: 360); - degreesControl.VAnchor = Agg.UI.VAnchor.ParentTop; - degreesContainer.AddChild(degreesControl); - - buttonPanel.AddChild(degreesContainer); - - FlowLayoutWidget rotateButtonContainer = new FlowLayoutWidget(FlowDirection.LeftToRight); - rotateButtonContainer.HAnchor = HAnchor.ParentLeftRight; - - buttonPanel.AddChild(rotateButtonContainer); - - buttonPanel.AddChild(generateHorizontalRule()); - textImageButtonFactory.FixedWidth = 0; - } - - private GuiWidget generateHorizontalRule() - { - GuiWidget horizontalRule = new GuiWidget(); - horizontalRule.Height = 1; - horizontalRule.Margin = new BorderDouble(0, 1, 0, 3); - horizontalRule.HAnchor = HAnchor.ParentLeftRight; - horizontalRule.BackgroundColor = new RGBA_Bytes(255, 255, 255, 200); - return horizontalRule; - } - - private void AddHandlers() - { - closeButton.Click += onCloseButton_Click; - - saveButton.Click += (sender, e) => - { - MergeAndSavePartsToStl(); - }; - - saveAndExitButton.Click += (sender, e) => - { - MergeAndSavePartsToStl(); - }; - } - - private bool partSelectButtonWasClicked = false; - - private async void MergeAndSavePartsToStl() - { - if (MeshGroups.Count > 0) - { - partSelectButtonWasClicked = viewControls3D.ActiveButton == ViewControls3DButtons.PartSelect; - - processingProgressControl.ProcessType = "Saving Parts:".Localize(); - processingProgressControl.Visible = true; - processingProgressControl.PercentComplete = 0; - LockEditControls(); - - // we sent the data to the async lists but we will not pull it back out (only use it as a temp holder). - PushMeshGroupDataToAsynchLists(true); - - string fileName = "BrailleBuilder_{0}".FormatWith(Path.ChangeExtension(Path.GetRandomFileName(), ".amf")); - string filePath = Path.Combine(ApplicationDataStorage.Instance.ApplicationLibraryDataPath, fileName); - - processingProgressControl.RatioComplete = 0; - await Task.Run(() => MergeAndSavePartsDoWork(filePath)); - - PrintItem printItem = new PrintItem(); - - printItem.Name = string.Format("{0}", word); - printItem.FileLocation = Path.GetFullPath(filePath); - - PrintItemWrapper printItemWrapper = new PrintItemWrapper(printItem); - - // and save to the queue - QueueData.Instance.AddItem(printItemWrapper); - - //Exit after save - UiThread.RunOnIdle(CloseOnIdle); - } - } - - private void MergeAndSavePartsDoWork(string filePath) - { - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - try - { - // push all the transforms into the meshes - for (int i = 0; i < asyncMeshGroups.Count; i++) - { - asyncMeshGroups[i].Transform(MeshGroupTransforms[i]); - - processingProgressControl.RatioComplete = (double)i / asyncMeshGroups.Count * .1; - } - - MeshFileIo.Save(asyncMeshGroups, filePath); - } - catch (System.UnauthorizedAccessException) - { - //Do something special when unauthorized? - StyledMessageBox.ShowMessageBox(null, "Oops! Unable to save changes.".Localize(), "Unable to save".Localize()); - } - catch - { - StyledMessageBox.ShowMessageBox(null, "Oops! Unable to save changes.".Localize(), "Unable to save".Localize()); - } - } - - private bool scaleQueueMenu_Click() - { - return true; - } - - private bool rotateQueueMenu_Click() - { - return true; - } - - private void onCloseButton_Click(object sender, EventArgs e) - { - UiThread.RunOnIdle(Close); - } - } -} \ No newline at end of file diff --git a/BrailleBuilder/app.config b/BrailleBuilder/app.config deleted file mode 100644 index a176ba41b..000000000 --- a/BrailleBuilder/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/CustomWidgets/ExportPrintItemWindow.cs b/CustomWidgets/ExportPrintItemWindow.cs index 75c3939f0..3680751c7 100644 --- a/CustomWidgets/ExportPrintItemWindow.cs +++ b/CustomWidgets/ExportPrintItemWindow.cs @@ -1,6 +1,7 @@ using MatterHackers.Agg; using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.GCodeVisualizer; using MatterHackers.Localizations; using MatterHackers.MatterControl.ConfigurationPage.PrintLeveling; @@ -128,8 +129,7 @@ namespace MatterHackers.MatterControl bool showExportGCodeButton = ActiveSliceSettings.Instance.PrinterSelected || partIsGCode; if (showExportGCodeButton) { - string exportGCodeTextFull = string.Format("{0} G-Code", "Export as".Localize()); - Button exportGCode = textImageButtonFactory.Generate(exportGCodeTextFull); + Button exportGCode = textImageButtonFactory.Generate(string.Format("{0} G-Code", "Export as".Localize())); exportGCode.Name = "Export as GCode Button"; exportGCode.HAnchor = HAnchor.ParentLeft; exportGCode.Cursor = Cursors.Hand; @@ -146,7 +146,6 @@ namespace MatterHackers.MatterControl if (plugin.EnabledForCurrentPart(printItemWrapper)) { //Create export button for each Plugin found - string exportButtonText = plugin.GetButtonText().Localize(); Button exportButton = textImageButtonFactory.Generate(exportButtonText); @@ -413,10 +412,12 @@ namespace MatterHackers.MatterControl { UiThread.RunOnIdle(() => { - SaveFileDialogParams saveParams = new SaveFileDialogParams("Save as AMF|*.amf", initialDirectory: documentsPath); - saveParams.Title = "MatterControl: Export File"; - saveParams.ActionButtonLabel = "Export"; - saveParams.FileName = printItemWrapper.Name; + SaveFileDialogParams saveParams = new SaveFileDialogParams("Save as AMF|*.amf", initialDirectory: documentsPath) + { + Title = "MatterControl: Export File", + ActionButtonLabel = "Export", + FileName = printItemWrapper.Name + }; Close(); FileDialog.SaveFileDialog(saveParams, onExportAmfFileSelected); @@ -449,13 +450,8 @@ namespace MatterHackers.MatterControl } else { - List meshGroups = MeshFileIo.Load(printItemWrapper.FileLocation); - if (!MeshFileIo.Save(meshGroups, filePathToSave)) - { - UiThread.RunOnIdle (() => { - StyledMessageBox.ShowMessageBox(null, "STL to AMF conversion failed", "Couldn't save file".Localize()); - }); - } + IObject3D item = Object3D.Load(printItemWrapper.FileLocation); + MeshFileIo.Save(item, filePathToSave); } ShowFileIfRequested(filePathToSave); } @@ -509,8 +505,9 @@ namespace MatterHackers.MatterControl } else { - List meshGroups = MeshFileIo.Load(printItemWrapper.FileLocation); - if (!MeshFileIo.Save(meshGroups, filePathToSave)) + IObject3D loadedItem = Object3D.Load(printItemWrapper.FileLocation); + + if (!MeshFileIo.Save(new List { loadedItem.Flatten() }, filePathToSave)) { UiThread.RunOnIdle (() => { StyledMessageBox.ShowMessageBox(null, "AMF to STL conversion failed", "Couldn't save file".Localize()); diff --git a/CustomWidgets/PartThumbnailWidget.cs b/CustomWidgets/PartThumbnailWidget.cs index 0cac0a8e3..add8618cb 100644 --- a/CustomWidgets/PartThumbnailWidget.cs +++ b/CustomWidgets/PartThumbnailWidget.cs @@ -46,6 +46,7 @@ using System.IO; using System.Threading.Tasks; using MatterHackers.Localizations; using MatterHackers.Agg.ImageProcessing; +using MatterHackers.DataConverters3D; namespace MatterHackers.MatterControl { @@ -70,6 +71,9 @@ namespace MatterHackers.MatterControl private static bool processingThumbnail = false; private ImageBuffer buildingThumbnailImage = new Agg.Image.ImageBuffer(); + // TODO: temporarily work around exception when trying to gen thumbnails for new file type + private bool supportsThumbnails = true; + private RGBA_Bytes normalBackgroundColor = ActiveTheme.Instance.PrimaryAccentColor; private ImageBuffer noThumbnailImage = new Agg.Image.ImageBuffer(); @@ -174,11 +178,17 @@ namespace MatterHackers.MatterControl } printItemWrapper = value; - + + supportsThumbnails = false; + thumbNailHasBeenCreated = false; if (ItemWrapper != null) { PrintItemWrapper.FileHasChanged.RegisterEvent(item_FileHasChanged, ref unregisterEvents); + + supportsThumbnails = !string.IsNullOrEmpty(printItemWrapper.FileLocation) && + File.Exists(printItemWrapper.FileLocation) && + Path.GetExtension(printItemWrapper.FileLocation).ToLower() != ".mcp"; } } } @@ -224,11 +234,17 @@ namespace MatterHackers.MatterControl } } } - + public override void OnDraw(Graphics2D graphics2D) { + if(ItemWrapper == null) + { + return; + } + //Trigger thumbnail generation if neeeded - if (!thumbNailHasBeenCreated && !processingThumbnail) + string stlHashCode = this.ItemWrapper.FileHashCode.ToString(); + if (!thumbNailHasBeenCreated && !processingThumbnail && supportsThumbnails) { if (SetImageFast()) { @@ -419,7 +435,7 @@ namespace MatterHackers.MatterControl return; } - List loadedMeshGroups = MeshFileIo.Load(this.ItemWrapper.FileLocation); + IObject3D loadedItem = Object3D.Load(this.ItemWrapper.FileLocation); RenderType renderType = GetRenderType(this.ItemWrapper.FileLocation); @@ -427,34 +443,28 @@ namespace MatterHackers.MatterControl { case RenderType.RAY_TRACE: { - ThumbnailTracer tracer = new ThumbnailTracer(loadedMeshGroups, BigRenderSize.x, BigRenderSize.y); + ThumbnailTracer tracer = new ThumbnailTracer(loadedItem, BigRenderSize.x, BigRenderSize.y); tracer.DoTrace(); - bigRender = tracer.destImage; + bigRender = (tracer.destImage != null) ? tracer.destImage : new ImageBuffer(this.noThumbnailImage); } break; case RenderType.PERSPECTIVE: { - ThumbnailTracer tracer = new ThumbnailTracer(loadedMeshGroups, BigRenderSize.x, BigRenderSize.y); + ThumbnailTracer tracer = new ThumbnailTracer(loadedItem, BigRenderSize.x, BigRenderSize.y); this.thumbnailImage = new ImageBuffer(this.buildingThumbnailImage); this.thumbnailImage.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); bigRender = new ImageBuffer(BigRenderSize.x, BigRenderSize.y); - foreach (MeshGroup meshGroup in loadedMeshGroups) + foreach (IObject3D item in loadedItem.Children) { double minZ = double.MaxValue; double maxZ = double.MinValue; - foreach (Mesh loadedMesh in meshGroup.Meshes) - { - tracer.GetMinMaxZ(loadedMesh, ref minZ, ref maxZ); - } - foreach (Mesh loadedMesh in meshGroup.Meshes) - { - tracer.DrawTo(bigRender.NewGraphics2D(), loadedMesh, RGBA_Bytes.White, minZ, maxZ); - } + tracer.GetMinMaxZ(item.Mesh, ref minZ, ref maxZ); + tracer.DrawTo(bigRender.NewGraphics2D(), item.Mesh, RGBA_Bytes.White, minZ, maxZ); } if (bigRender == null) @@ -469,7 +479,7 @@ namespace MatterHackers.MatterControl this.thumbnailImage = new ImageBuffer(this.buildingThumbnailImage); this.thumbnailImage.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); - bigRender = BuildImageFromMeshGroups(loadedMeshGroups, stlHashCode, BigRenderSize); + bigRender = BuildImageFromMeshGroups(loadedItem.ToMeshGroupList(), stlHashCode, BigRenderSize); if (bigRender == null) { bigRender = new ImageBuffer(this.noThumbnailImage); diff --git a/CustomWidgets/ThumbnailTracer.cs b/CustomWidgets/ThumbnailTracer.cs index 5a2e6445d..1079ef226 100644 --- a/CustomWidgets/ThumbnailTracer.cs +++ b/CustomWidgets/ThumbnailTracer.cs @@ -44,6 +44,7 @@ namespace MatterHackers.RayTracer using MatterHackers.Agg.RasterizerScanline; using MatterHackers.Agg.VertexSource; using MatterHackers.RayTracer.Light; + using System.Linq; public class ThumbnailTracer { @@ -55,6 +56,8 @@ namespace MatterHackers.RayTracer private List loadedMeshGroups; + private bool hasOneOrMoreMesh; + private RayTracer rayTracer = new RayTracer() { //AntiAliasing = AntiAliasing.None, @@ -69,21 +72,32 @@ namespace MatterHackers.RayTracer private Scene scene; private Point2D size; public TrackballTumbleWidget trackballTumbleWidget; - public ThumbnailTracer(List meshGroups, int width, int height) + + public ThumbnailTracer(IObject3D item, int width, int height) { size = new Point2D(width, height); trackballTumbleWidget = new TrackballTumbleWidget(); trackballTumbleWidget.DoOpenGlDrawing = false; trackballTumbleWidget.LocalBounds = new RectangleDouble(0, 0, width, height); - loadedMeshGroups = meshGroups; - SetRenderPosition(loadedMeshGroups); + loadedMeshGroups = item.ToMeshGroupList(); - trackballTumbleWidget.AnchorCenter(); + hasOneOrMoreMesh = loadedMeshGroups.SelectMany(mg => mg.Meshes).Where(mesh => mesh != null).Any(); + if (hasOneOrMoreMesh) + { + SetRenderPosition(loadedMeshGroups); + trackballTumbleWidget.AnchorCenter(); + } } public void DoTrace() { + if (!hasOneOrMoreMesh) + { + destImage = null; + return; + } + CreateScene(); RectangleInt rect = new RectangleInt(0, 0, size.x, size.y); if (destImage == null || destImage.Width != rect.Width || destImage.Height != rect.Height) @@ -100,7 +114,7 @@ namespace MatterHackers.RayTracer public void SetRenderPosition(List loadedMeshGroups) { trackballTumbleWidget.TrackBallController.Reset(); - trackballTumbleWidget.TrackBallController.Scale = .03; + trackballTumbleWidget.TrackBallController.Scale = .03; trackballTumbleWidget.TrackBallController.Rotate(Quaternion.FromEulerAngles(new Vector3(0, 0, MathHelper.Tau / 16))); trackballTumbleWidget.TrackBallController.Rotate(Quaternion.FromEulerAngles(new Vector3(-MathHelper.Tau * .19, 0, 0))); @@ -436,7 +450,7 @@ namespace MatterHackers.RayTracer public Ray GetRay(double screenX, double screenY) { - return trackballTumbleWidget.GetRayFromScreen(new Vector2(screenX, screenY)); + return trackballTumbleWidget.GetRayForLocalBounds(new Vector2(screenX, screenY)); } } } diff --git a/History/PrintHistoryListItem.cs b/History/PrintHistoryListItem.cs index 687f3e6f1..049603c78 100644 --- a/History/PrintHistoryListItem.cs +++ b/History/PrintHistoryListItem.cs @@ -375,7 +375,8 @@ namespace MatterHackers.MatterControl.PrintHistory { if (messageBoxResponse) { - QueueData.Instance.RemoveIndexOnIdle(QueueData.Instance.GetIndex(itemToRemove)); + int index = QueueData.Instance.GetIndex(itemToRemove); + UiThread.RunOnIdle(() => QueueData.Instance.RemoveAt(index)); } } diff --git a/Library/PrintLibraryWidget.cs b/Library/PrintLibraryWidget.cs index 1f91bafa9..6dafbfa4f 100644 --- a/Library/PrintLibraryWidget.cs +++ b/Library/PrintLibraryWidget.cs @@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project. using MatterHackers.Agg; using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MatterControl.CustomWidgets; using MatterHackers.MatterControl.CustomWidgets.LibrarySelector; diff --git a/Library/Provider/LibraryProvider.cs b/Library/Provider/LibraryProvider.cs index 53dd86cb6..d2cf51134 100644 --- a/Library/Provider/LibraryProvider.cs +++ b/Library/Provider/LibraryProvider.cs @@ -32,6 +32,7 @@ using MatterHackers.Agg.Image; using MatterHackers.Agg.ImageProcessing; using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.PolygonMesh; @@ -81,8 +82,7 @@ namespace MatterHackers.MatterControl.PrintLibrary.Provider { if (extension == ".ZIP") { - ProjectFileHandler project = new ProjectFileHandler(null); - List partFiles = project.ImportFromProjectArchive(loadedFileName); + List partFiles = ProjectFileHandler.ImportFromProjectArchive(loadedFileName); if (partFiles != null) { foreach (PrintItem part in partFiles) diff --git a/Library/Provider/LibraryProviderSqlite.cs b/Library/Provider/LibraryProviderSqlite.cs index 740e2f416..a2e3b284d 100644 --- a/Library/Provider/LibraryProviderSqlite.cs +++ b/Library/Provider/LibraryProviderSqlite.cs @@ -30,6 +30,7 @@ either expressed or implied, of the FreeBSD Project. using MatterHackers.Agg; using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.PrintQueue; @@ -409,7 +410,8 @@ namespace MatterHackers.MatterControl.PrintLibrary.Provider try { // Load mesh - List meshToConvertAndSave = MeshFileIo.Load(stream, extension); + IObject3D loadedItem = MeshFileIo.Load(stream, extension); + var meshToConvertAndSave = new List { loadedItem.Flatten() }; // Create a new PrintItemWrapper diff --git a/LocalizedString.cs b/LocalizedString.cs index 9306a947c..bdbbce0e8 100644 --- a/LocalizedString.cs +++ b/LocalizedString.cs @@ -45,8 +45,16 @@ namespace MatterHackers.Localizations if (MatterControlTranslationMap == null) { #if DEBUG && !__ANDROID__ - // In debug builds we load a translation map capable of generating/updating master.txt - MatterControlTranslationMap = new AutoGeneratingTranslationMap("Translations", UserSettings.Instance.Language); + if (!System.Environment.CurrentDirectory.ToLower().Contains(".tests")) + { + // In debug builds we load a translation map capable of generating/updating master.txt + MatterControlTranslationMap = new AutoGeneratingTranslationMap("Translations", UserSettings.Instance.Language); + } + else + { + // Create a pass through TranslationMap for tests by requesting a non-existing language name + MatterControlTranslationMap = new TranslationMap("Translations", "NA"); + } #else MatterControlTranslationMap = new TranslationMap("Translations", UserSettings.Instance.Language); #endif diff --git a/MatterControl.csproj b/MatterControl.csproj index 3c6dc300c..57019eff9 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -185,21 +185,25 @@ + + - + - + + + @@ -246,7 +250,6 @@ - @@ -270,6 +273,7 @@ + @@ -425,6 +429,7 @@ + diff --git a/MatterControl.sln b/MatterControl.sln index 1b249ffde..36c14a26b 100644 --- a/MatterControl.sln +++ b/MatterControl.sln @@ -101,8 +101,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatterSlice.Tests", "Submod EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuiAutomation", "Submodules\agg-sharp\GuiAutomation\GuiAutomation.csproj", "{E9102310-0029-4D8F-B1E9-88FBA6147D45}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrailleBuilder", "BrailleBuilder\BrailleBuilder.csproj", "{70FBB82C-558D-4B5F-BE75-A922D392E650}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataConverters2D", "Submodules\agg-sharp\DataConverters2D\DataConverters2D.csproj", "{94838988-523C-4B11-AD82-8B9B76F23A31}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatterControl.AutomationTests", "Tests\MatterControl.AutomationTests\MatterControl.AutomationTests.csproj", "{418E7058-92EE-4329-86BA-AC26B65AFB25}" @@ -946,34 +944,6 @@ Global {E9102310-0029-4D8F-B1E9-88FBA6147D45}.Release64|x64.Build.0 = Release64|x64 {E9102310-0029-4D8F-B1E9-88FBA6147D45}.Release64|x86.ActiveCfg = Release64|Any CPU {E9102310-0029-4D8F-B1E9-88FBA6147D45}.Release64|x86.Build.0 = Release64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug|Any CPU.Build.0 = Debug|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug|x64.ActiveCfg = Debug|x64 - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug|x64.Build.0 = Debug|x64 - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug|x86.ActiveCfg = Debug|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug64|Any CPU.ActiveCfg = Debug64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug64|Any CPU.Build.0 = Debug64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug64|Mixed Platforms.ActiveCfg = Debug64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug64|Mixed Platforms.Build.0 = Debug64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug64|x64.ActiveCfg = Debug64|x64 - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug64|x64.Build.0 = Debug64|x64 - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Debug64|x86.ActiveCfg = Debug64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release|Any CPU.ActiveCfg = Release|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release|Any CPU.Build.0 = Release|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release|x64.ActiveCfg = Release|x64 - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release|x64.Build.0 = Release|x64 - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release|x86.ActiveCfg = Release|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release64|Any CPU.ActiveCfg = Release64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release64|Any CPU.Build.0 = Release64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release64|Mixed Platforms.ActiveCfg = Release64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release64|Mixed Platforms.Build.0 = Release64|Any CPU - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release64|x64.ActiveCfg = Release64|x64 - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release64|x64.Build.0 = Release64|x64 - {70FBB82C-558D-4B5F-BE75-A922D392E650}.Release64|x86.ActiveCfg = Release64|Any CPU {94838988-523C-4B11-AD82-8B9B76F23A31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {94838988-523C-4B11-AD82-8B9B76F23A31}.Debug|Any CPU.Build.0 = Debug|Any CPU {94838988-523C-4B11-AD82-8B9B76F23A31}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -1229,7 +1199,6 @@ Global {195CBE56-E654-437B-AB05-3BE1B9452497} = {FBE6DF29-85A9-4A8B-B739-35BE4CA0A9B7} {8CD15B23-D30F-470E-99BA-9276FB7CABD4} = {FBE6DF29-85A9-4A8B-B739-35BE4CA0A9B7} {E9102310-0029-4D8F-B1E9-88FBA6147D45} = {2AB9B589-5C98-4C05-BBEA-F97DAE168EAB} - {70FBB82C-558D-4B5F-BE75-A922D392E650} = {32E5B656-D6DF-415E-9E7E-D03F1D8C3A8A} {94838988-523C-4B11-AD82-8B9B76F23A31} = {2AB9B589-5C98-4C05-BBEA-F97DAE168EAB} {418E7058-92EE-4329-86BA-AC26B65AFB25} = {FBE6DF29-85A9-4A8B-B739-35BE4CA0A9B7} {7EE4636D-8A92-4015-9562-7FCD6ADD0645} = {2AB9B589-5C98-4C05-BBEA-F97DAE168EAB} diff --git a/MatterControlApplication.cs b/MatterControlApplication.cs index 63b11d825..02535238e 100644 --- a/MatterControlApplication.cs +++ b/MatterControlApplication.cs @@ -32,6 +32,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; +using System.Linq; using System.Net; using System.Threading; using Gaming.Game; @@ -39,8 +40,10 @@ using MatterHackers.Agg; using MatterHackers.Agg.Image; using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MatterControl.DataStorage; +using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MatterControl.PluginSystem; using MatterHackers.MatterControl.PrinterCommunication; using MatterHackers.MatterControl.PrintQueue; @@ -72,7 +75,7 @@ namespace MatterHackers.MatterControl private bool DoCGCollectEveryDraw = false; private int drawCount = 0; private AverageMillisecondTimer millisecondTimer = new AverageMillisecondTimer(); - private DataViewGraph msGraph; + private DataViewGraph msGraph = new DataViewGraph(50, 50, 0, 200); private string savePartsSheetExitAnywayMessage = "You are currently saving a parts sheet, are you sure you want to exit?".Localize(); private bool ShowMemoryUsed = false; @@ -219,7 +222,7 @@ namespace MatterHackers.MatterControl break; case "SLICE_AND_EXPORT_GCODE": - if (currentCommandIndex + 1 <= commandLineArgs.Length) + if (currentCommandIndex + 1 <= commandLineArgs.Length) { currentCommandIndex++; string fullPath = commandLineArgs[currentCommandIndex]; @@ -431,6 +434,8 @@ namespace MatterHackers.MatterControl private static Vector2 minSize { get; set; } = new Vector2(600, 600); + public View3DWidget ActiveView3DWidget { get; internal set; } + public static MatterControlApplication CreateInstance(int overrideWidth = -1, int overrideHeight = -1) { int width = 0; @@ -725,6 +730,11 @@ namespace MatterHackers.MatterControl //HtmlWindowTest(); IsLoading = false; + +#if DEBUG + AfterDraw += ShowNamesUnderMouse; +#endif + base.OnLoad(args); } private static void HtmlWindowTest() @@ -767,6 +777,14 @@ namespace MatterHackers.MatterControl public override void OnMouseMove(MouseEventArgs mouseEvent) { +#if DEBUG + if (showNamesUnderMouse) + { + mousePosition = mouseEvent.Position; + Invalidate(); + } +#endif + if (GuiWidget.DebugBoundsUnderMouse) { Invalidate(); @@ -896,6 +914,33 @@ namespace MatterHackers.MatterControl private bool showNamesUnderMouse = false; +#if DEBUG + Vector2 mousePosition; + private void ShowNamesUnderMouse(object sender, DrawEventArgs e) + { + if (showNamesUnderMouse) + { + List namedChildren = new List(); + this.FindNamedChildrenRecursive("", namedChildren, new RectangleDouble(mousePosition.x, mousePosition.y, mousePosition.x + 1 , mousePosition.y + 1), SearchType.Partial); + Vector2 start = new Vector2(10, 50); + int lineHeight = 20; + e.graphics2D.FillRectangle(start, start + new Vector2(500, namedChildren.Count * lineHeight), new RGBA_Bytes(RGBA_Bytes.Black, 120)); + foreach(var child in namedChildren) + { + if (child.name != null) + { + e.graphics2D.DrawString($"{child.widget.GetType().Name} --- {child.name}", start.x, start.y, backgroundColor: RGBA_Bytes.White, drawFromHintedCach: true); + start.y += lineHeight; + } + else + { + //e.graphics2D.DrawString($"{child.widget.GetType().Name} -- -", start.x, start.y, backgroundColor: RGBA_Bytes.White, drawFromHintedCach: true); + //start.y += lineHeight; + } + } + } + } + public override void OnKeyDown(KeyEventArgs keyEvent) { if (keyEvent.KeyCode == Keys.F1) @@ -904,7 +949,7 @@ namespace MatterHackers.MatterControl } base.OnKeyDown(keyEvent); } - +#endif public static void CheckKnownAssemblyConditionalCompSymbols() { MatterControlApplication.AssertDebugNotDefined(); diff --git a/PartPreviewWindow/BaseClasses/PartPreview3DWidget.cs b/PartPreviewWindow/BaseClasses/PartPreview3DWidget.cs index 26b06e4ba..7c19879bd 100644 --- a/PartPreviewWindow/BaseClasses/PartPreview3DWidget.cs +++ b/PartPreviewWindow/BaseClasses/PartPreview3DWidget.cs @@ -31,8 +31,11 @@ using MatterHackers.Agg; using MatterHackers.Agg.Image; using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.MatterControl.SlicerConfiguration; using MatterHackers.MeshVisualizer; +using MatterHackers.PolygonMesh; +using MatterHackers.RayTracer; using MatterHackers.VectorMath; using System; using System.IO; @@ -42,13 +45,17 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public abstract class PartPreview3DWidget : PartPreviewWidget { protected static readonly int DefaultScrollBarWidth = 120; - + protected bool autoRotating = false; protected bool allowAutoRotate = false; + public MeshViewerWidget meshViewerWidget; private EventHandler unregisterEvents; + // Proxy to MeshViewerWidget + public InteractiveScene Scene => meshViewerWidget.Scene; + protected ViewControls3D viewControls3D; private bool needToRecretaeBed = false; @@ -59,6 +66,41 @@ namespace MatterHackers.MatterControl.PartPreviewWindow ApplicationController.Instance.AdvancedControlsPanelReloading.RegisterEvent(CheckSettingChanged, ref unregisterEvents); } + public MeshSelectInfo CurrentSelectInfo { get; private set; } = new MeshSelectInfo(); + + protected IObject3D FindHitObject3D(Vector2 screenPosition, ref IntersectInfo intersectionInfo) + { + Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, screenPosition); + Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayForLocalBounds(meshViewerWidgetScreenPosition); + + intersectionInfo = Scene.TraceData().GetClosestIntersection(ray); + if (intersectionInfo != null) + { + foreach (Object3D object3D in Scene.Children) + { + if (object3D.TraceData().Contains(intersectionInfo.closestHitObject)) + { + CurrentSelectInfo.PlaneDownHitPos = intersectionInfo.hitPosition; + CurrentSelectInfo.LastMoveDelta = new Vector3(); + return object3D; + } + } + } + + return null; + } + + public GuiWidget GenerateHorizontalRule() + { + return new GuiWidget() + { + Height = 1, + Margin = new BorderDouble(0, 1, 0, 3), + HAnchor = HAnchor.ParentLeftRight, + BackgroundColor = new RGBA_Bytes(255, 255, 255, 200) + }; + } + private void CheckSettingChanged(object sender, EventArgs e) { StringEventArgs stringEvent = e as StringEventArgs; @@ -93,6 +135,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow if(ActiveSliceSettings.Instance.GetValue(SettingsKey.center_part_on_bed) && !InEditMode) { + #if false if (meshViewerWidget.MeshGroups.Count > 0) { var bounds = meshViewerWidget.MeshGroups[0].GetAxisAlignedBoundingBox(); @@ -102,6 +145,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow meshViewerWidget.MeshGroupTransforms[i] = Matrix4X4.CreateTranslation(-boundsCenter + new Vector3(0, 0, bounds.ZSize / 2) + new Vector3(bedCenter)); } } + #endif } })); } @@ -143,7 +187,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow base.OnClosed(e); } - protected static SolidSlider InsertUiForSlider(FlowLayoutWidget wordOptionContainer, string header, double min = 0, double max = .5) + public static SolidSlider InsertUiForSlider(GuiWidget wordOptionContainer, string header, double min = 0, double max = .5) { double scrollBarWidth = 10; if (UserSettings.Instance.IsTouchScreen) @@ -151,17 +195,23 @@ namespace MatterHackers.MatterControl.PartPreviewWindow scrollBarWidth = 20; } - TextWidget spacingText = new TextWidget(header, textColor: ActiveTheme.Instance.PrimaryTextColor); - spacingText.Margin = new BorderDouble(10, 3, 3, 5); - spacingText.HAnchor = HAnchor.ParentLeft; + TextWidget spacingText = new TextWidget(header, textColor: ActiveTheme.Instance.PrimaryTextColor) + { + Margin = new BorderDouble(10, 3, 3, 5), + HAnchor = HAnchor.ParentLeft + }; wordOptionContainer.AddChild(spacingText); - SolidSlider namedSlider = new SolidSlider(new Vector2(), scrollBarWidth, 0, 1); - namedSlider.TotalWidthInPixels = DefaultScrollBarWidth; - namedSlider.Minimum = min; - namedSlider.Maximum = max; - namedSlider.Margin = new BorderDouble(3, 5, 3, 3); - namedSlider.HAnchor = HAnchor.ParentCenter; + + SolidSlider namedSlider = new SolidSlider(new Vector2(), scrollBarWidth, 0, 1) + { + TotalWidthInPixels = DefaultScrollBarWidth, + Minimum = min, + Maximum = max, + Margin = new BorderDouble(3, 5, 3, 3), + HAnchor = HAnchor.ParentCenter, + }; namedSlider.View.BackgroundColor = new RGBA_Bytes(); + wordOptionContainer.AddChild(namedSlider); return namedSlider; diff --git a/PartPreviewWindow/BaseClasses/PartPreviewWidget.cs b/PartPreviewWindow/BaseClasses/PartPreviewWidget.cs index 41d320815..30f0b0b6c 100644 --- a/PartPreviewWindow/BaseClasses/PartPreviewWidget.cs +++ b/PartPreviewWindow/BaseClasses/PartPreviewWidget.cs @@ -37,10 +37,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow protected readonly int ShortButtonHeight = 25; protected int SideBarButtonWidth; - public TextImageButtonFactory textImageButtonFactory = new TextImageButtonFactory(); - protected TextImageButtonFactory checkboxButtonFactory = new TextImageButtonFactory(); - public TextImageButtonFactory ExpandMenuOptionFactory = new TextImageButtonFactory(); - public TextImageButtonFactory WhiteButtonFactory = new TextImageButtonFactory(); + public TextImageButtonFactory textImageButtonFactory; + protected TextImageButtonFactory checkboxButtonFactory; + public TextImageButtonFactory ExpandMenuOptionFactory; + public TextImageButtonFactory WhiteButtonFactory; protected ViewControls2D viewControls2D; @@ -60,49 +60,63 @@ namespace MatterHackers.MatterControl.PartPreviewWindow ShortButtonHeight = 30; } - textImageButtonFactory.normalTextColor = ActiveTheme.Instance.PrimaryTextColor; - textImageButtonFactory.hoverTextColor = ActiveTheme.Instance.PrimaryTextColor; - textImageButtonFactory.pressedTextColor = ActiveTheme.Instance.PrimaryTextColor; - - textImageButtonFactory.disabledTextColor = ActiveTheme.Instance.TabLabelUnselected; - textImageButtonFactory.disabledFillColor = new RGBA_Bytes(); + textImageButtonFactory = new TextImageButtonFactory() + { + normalTextColor = ActiveTheme.Instance.PrimaryTextColor, + hoverTextColor = ActiveTheme.Instance.PrimaryTextColor, + pressedTextColor = ActiveTheme.Instance.PrimaryTextColor, + disabledTextColor = ActiveTheme.Instance.TabLabelUnselected, + disabledFillColor = new RGBA_Bytes() + }; + WhiteButtonFactory = new TextImageButtonFactory() + { + FixedWidth = SideBarButtonWidth, + FixedHeight = ShortButtonHeight, - WhiteButtonFactory.FixedWidth = SideBarButtonWidth; - WhiteButtonFactory.FixedHeight = ShortButtonHeight; - WhiteButtonFactory.normalFillColor = RGBA_Bytes.White; - WhiteButtonFactory.normalTextColor = RGBA_Bytes.Black; - WhiteButtonFactory.hoverTextColor = RGBA_Bytes.Black; - WhiteButtonFactory.hoverFillColor = new RGBA_Bytes(255, 255, 255, 200); - WhiteButtonFactory.borderWidth = 1; - WhiteButtonFactory.normalBorderColor = new RGBA_Bytes(ActiveTheme.Instance.PrimaryTextColor, 200); - WhiteButtonFactory.hoverBorderColor = new RGBA_Bytes(ActiveTheme.Instance.PrimaryTextColor, 200); + normalFillColor = RGBA_Bytes.White, + normalTextColor = RGBA_Bytes.Black, + hoverTextColor = RGBA_Bytes.Black, - ExpandMenuOptionFactory.FixedWidth = SideBarButtonWidth; - ExpandMenuOptionFactory.normalTextColor = ActiveTheme.Instance.PrimaryTextColor; - ExpandMenuOptionFactory.hoverTextColor = ActiveTheme.Instance.PrimaryTextColor; - ExpandMenuOptionFactory.disabledTextColor = ActiveTheme.Instance.PrimaryTextColor; - ExpandMenuOptionFactory.pressedTextColor = ActiveTheme.Instance.PrimaryTextColor; - ExpandMenuOptionFactory.hoverFillColor = new RGBA_Bytes(255, 255, 255, 50); - ExpandMenuOptionFactory.pressedFillColor = new RGBA_Bytes(255, 255, 255, 50); - ExpandMenuOptionFactory.disabledFillColor = new RGBA_Bytes(255, 255, 255, 50); + hoverFillColor = new RGBA_Bytes(255, 255, 255, 200), + borderWidth = 1, - checkboxButtonFactory.fontSize = 11; - checkboxButtonFactory.FixedWidth = SideBarButtonWidth; - checkboxButtonFactory.borderWidth = 3; + normalBorderColor = new RGBA_Bytes(ActiveTheme.Instance.PrimaryTextColor, 200), + hoverBorderColor = new RGBA_Bytes(ActiveTheme.Instance.PrimaryTextColor, 200) + }; - checkboxButtonFactory.normalTextColor = ActiveTheme.Instance.PrimaryTextColor; - checkboxButtonFactory.normalBorderColor = new RGBA_Bytes(0, 0, 0, 0); - checkboxButtonFactory.normalFillColor = ActiveTheme.Instance.PrimaryBackgroundColor; + ExpandMenuOptionFactory = new TextImageButtonFactory() + { + FixedWidth = SideBarButtonWidth, + normalTextColor = ActiveTheme.Instance.PrimaryTextColor, + hoverTextColor = ActiveTheme.Instance.PrimaryTextColor, + disabledTextColor = ActiveTheme.Instance.PrimaryTextColor, + pressedTextColor = ActiveTheme.Instance.PrimaryTextColor, - checkboxButtonFactory.hoverTextColor = ActiveTheme.Instance.PrimaryTextColor; - checkboxButtonFactory.hoverBorderColor = new RGBA_Bytes(0, 0, 0, 50); - checkboxButtonFactory.hoverFillColor = new RGBA_Bytes(0, 0, 0, 50); + hoverFillColor = new RGBA_Bytes(255, 255, 255, 50), + pressedFillColor = new RGBA_Bytes(255, 255, 255, 50), + disabledFillColor = new RGBA_Bytes(255, 255, 255, 50) + }; - checkboxButtonFactory.pressedTextColor = ActiveTheme.Instance.PrimaryTextColor; - checkboxButtonFactory.pressedBorderColor = new RGBA_Bytes(0, 0, 0, 50); + checkboxButtonFactory = new TextImageButtonFactory() + { + fontSize = 11, + FixedWidth = SideBarButtonWidth, + borderWidth = 3, - checkboxButtonFactory.disabledTextColor = ActiveTheme.Instance.PrimaryTextColor; + normalTextColor = ActiveTheme.Instance.PrimaryTextColor, + normalBorderColor = new RGBA_Bytes(0, 0, 0, 0), + normalFillColor = ActiveTheme.Instance.PrimaryBackgroundColor, + + hoverTextColor = ActiveTheme.Instance.PrimaryTextColor, + hoverBorderColor = new RGBA_Bytes(0, 0, 0, 50), + hoverFillColor = new RGBA_Bytes(0, 0, 0, 50), + + pressedTextColor = ActiveTheme.Instance.PrimaryTextColor, + pressedBorderColor = new RGBA_Bytes(0, 0, 0, 50), + + disabledTextColor = ActiveTheme.Instance.PrimaryTextColor + }; BackgroundColor = RGBA_Bytes.White; } diff --git a/PartPreviewWindow/PartPreviewContent.cs b/PartPreviewWindow/PartPreviewContent.cs index a0b940c2d..b9f855529 100644 --- a/PartPreviewWindow/PartPreviewContent.cs +++ b/PartPreviewWindow/PartPreviewContent.cs @@ -31,6 +31,7 @@ using MatterHackers.Agg; using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.UI; using MatterHackers.Localizations; +using MatterHackers.MatterControl.PrinterCommunication; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.MatterControl.SlicerConfiguration; using MatterHackers.MeshVisualizer; @@ -52,15 +53,27 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private View3DWidget.OpenMode openMode; private View3DWidget.WindowMode windowMode; + PrintItemWrapper printItem; + public PartPreviewContent(PrintItemWrapper printItem, View3DWidget.WindowMode windowMode, View3DWidget.AutoRotate autoRotate3DView, View3DWidget.OpenMode openMode = View3DWidget.OpenMode.Viewing) { + this.printItem = printItem; this.openMode = openMode; this.autoRotate3DView = autoRotate3DView; this.windowMode = windowMode; BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; this.AnchorAll(); - this.Load(printItem); + this.LoadPrintItem(printItem); + + PrinterConnectionAndCommunication.Instance.ActivePrintItemChanged.RegisterEvent((s, e) => + { + if (windowMode == View3DWidget.WindowMode.Embeded) + { + this.printItem = PrinterConnectionAndCommunication.Instance.ActivePrintItem; + LoadActivePrintItem(); + } + }, ref unregisterEvents); // We do this after showing the system window so that when we try and take focus of the parent window (the system window) // it exists and can give the focus to its child the gcode window. @@ -74,10 +87,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public void Reload(PrintItemWrapper printItem) { this.CloseAllChildren(); - this.Load(printItem); + this.LoadPrintItem(printItem); } - private void Load(PrintItemWrapper printItem) + private async void LoadActivePrintItem() + { + await partPreviewView.ClearBedAndLoadPrintItemWrapper(printItem); + viewGcodeBasic.LoadItem(printItem); + } + + private void LoadPrintItem(PrintItemWrapper printItem) { tabControl = new TabControl(); tabControl.TabBar.BorderColor = new RGBA_Bytes(0, 0, 0, 0); @@ -116,7 +135,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow gcodeWindowMode = ViewGcodeBasic.WindowMode.StandAlone; } - viewGcodeBasic = new ViewGcodeBasic(printItem, + viewGcodeBasic = new ViewGcodeBasic( new Vector3(ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_size), buildHeight), ActiveSliceSettings.Instance.GetValue(SettingsKey.print_center), ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_shape), gcodeWindowMode); @@ -155,6 +174,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow this.AddChild(tabControl); } + public override void OnLoad(EventArgs args) + { + MatterControlApplication.Instance.ActiveView3DWidget = partPreviewView; + + LoadActivePrintItem(); + + base.OnLoad(args); + } + public void SwitchToGcodeView() { tabControl.TabBar.SelectTab(layerViewTab); diff --git a/PartPreviewWindow/PlatingHelper.cs b/PartPreviewWindow/PlatingHelper.cs index 4372cbbb7..255df14fd 100644 --- a/PartPreviewWindow/PlatingHelper.cs +++ b/PartPreviewWindow/PlatingHelper.cs @@ -39,18 +39,14 @@ using System.Collections.Generic; namespace MatterHackers.MatterControl { + using DataConverters3D; using Localizations; using System.Collections; + using System.Linq; using Polygon = List; using Polygons = List>; - public class PlatingMeshGroupData - { - public Vector2 spacing; - public List meshTraceableData = new List(); - } - public static class PlatingHelper { public static PathStorage PolygonToPathStorage(Polygon polygon) @@ -105,31 +101,40 @@ namespace MatterHackers.MatterControl return output; } - public static void ArrangeMeshGroups(List asyncMeshGroups, List asyncMeshGroupTransforms, List asyncPlatingDatas, + public static void ArrangeMeshGroups(List object3DList, List asyncMeshGroupTransforms, List MeshGroupExtraData, + Action reportProgressChanged) + { + // TODO: ******************** !!!!!!!!!!!!!!! ******************** + } + + /* + public static void ArrangeMeshGroups(List object3DList, List asyncMeshGroupTransforms, List MeshGroupExtraData, Action reportProgressChanged) { + + // move them all out of the way - for (int i = 0; i < asyncMeshGroups.Count; i++) + for (int i = 0; i < MeshGroups.Count; i++) { asyncMeshGroupTransforms[i] *= Matrix4X4.CreateTranslation(10000, 10000, 0); } // sort them by size - for (int i = 0; i < asyncMeshGroups.Count; i++) + for (int i = 0; i < MeshGroups.Count; i++) { - AxisAlignedBoundingBox iAABB = asyncMeshGroups[i].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[i]); - for (int j = i + 1; j < asyncMeshGroups.Count; j++) + AxisAlignedBoundingBox iAABB = MeshGroups[i].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[i]); + for (int j = i + 1; j < MeshGroups.Count; j++) { - AxisAlignedBoundingBox jAABB = asyncMeshGroups[j].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[j]); + AxisAlignedBoundingBox jAABB = MeshGroups[j].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[j]); if (Math.Max(iAABB.XSize, iAABB.YSize) < Math.Max(jAABB.XSize, jAABB.YSize)) { - PlatingMeshGroupData tempData = asyncPlatingDatas[i]; - asyncPlatingDatas[i] = asyncPlatingDatas[j]; - asyncPlatingDatas[j] = tempData; + PlatingMeshGroupData tempData = MeshGroupExtraData[i]; + MeshGroupExtraData[i] = MeshGroupExtraData[j]; + MeshGroupExtraData[j] = tempData; - MeshGroup tempMeshGroup = asyncMeshGroups[i]; - asyncMeshGroups[i] = asyncMeshGroups[j]; - asyncMeshGroups[j] = tempMeshGroup; + MeshGroup tempMeshGroup = MeshGroups[i]; + MeshGroups[i] = MeshGroups[j]; + MeshGroups[j] = tempMeshGroup; Matrix4X4 iTransform = asyncMeshGroupTransforms[i]; Matrix4X4 jTransform = asyncMeshGroupTransforms[j]; @@ -145,61 +150,60 @@ namespace MatterHackers.MatterControl } } - double ratioPerMeshGroup = 1.0 / asyncMeshGroups.Count; + double ratioPerMeshGroup = 1.0 / MeshGroups.Count; double currentRatioDone = 0; // put them onto the plate (try the center) starting with the biggest and moving down - for (int meshGroupIndex = 0; meshGroupIndex < asyncMeshGroups.Count; meshGroupIndex++) + for (int meshGroupIndex = 0; meshGroupIndex < MeshGroups.Count; meshGroupIndex++) { reportProgressChanged(currentRatioDone, "Calculating Positions...".Localize()); - MeshGroup meshGroup = asyncMeshGroups[meshGroupIndex]; + MeshGroup meshGroup = MeshGroups[meshGroupIndex]; Vector3 meshLowerLeft = meshGroup.GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[meshGroupIndex]).minXYZ; asyncMeshGroupTransforms[meshGroupIndex] *= Matrix4X4.CreateTranslation(-meshLowerLeft); - PlatingHelper.MoveMeshGroupToOpenPosition(meshGroupIndex, asyncPlatingDatas, asyncMeshGroups, asyncMeshGroupTransforms); + PlatingHelper.MoveMeshGroupToOpenPosition(meshGroupIndex, MeshGroupExtraData, MeshGroups, asyncMeshGroupTransforms); // and create the trace info so we can select it - if (asyncPlatingDatas[meshGroupIndex].meshTraceableData.Count == 0) + if (MeshGroupExtraData[meshGroupIndex].meshTraceableData.Count == 0) { - PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, meshGroupIndex, null); + PlatingHelper.CreateITraceableForMeshGroup(MeshGroupExtraData, MeshGroups, meshGroupIndex, null); } currentRatioDone += ratioPerMeshGroup; // and put it on the bed - PlatingHelper.PlaceMeshGroupOnBed(asyncMeshGroups, asyncMeshGroupTransforms, meshGroupIndex); + PlatingHelper.PlaceMeshGroupOnBed(MeshGroups, asyncMeshGroupTransforms, meshGroupIndex); } // and finally center whatever we have as a group { - AxisAlignedBoundingBox bounds = asyncMeshGroups[0].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[0]); - for (int i = 1; i < asyncMeshGroups.Count; i++) + AxisAlignedBoundingBox bounds = MeshGroups[0].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[0]); + for (int i = 1; i < MeshGroups.Count; i++) { - bounds = AxisAlignedBoundingBox.Union(bounds, asyncMeshGroups[i].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[i])); + bounds = AxisAlignedBoundingBox.Union(bounds, MeshGroups[i].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[i])); } Vector3 boundsCenter = (bounds.maxXYZ + bounds.minXYZ) / 2; - for (int i = 0; i < asyncMeshGroups.Count; i++) + for (int i = 0; i < MeshGroups.Count; i++) { asyncMeshGroupTransforms[i] *= Matrix4X4.CreateTranslation(-boundsCenter + new Vector3(0, 0, bounds.ZSize / 2)); } } } - - public static void PlaceMeshGroupOnBed(List meshesGroupList, List meshTransforms, int index) + */ + public static void PlaceMeshGroupOnBed(IObject3D object3D) { - AxisAlignedBoundingBox bounds = GetAxisAlignedBoundingBox(meshesGroupList[index], meshTransforms[index]); + AxisAlignedBoundingBox bounds = object3D.GetAxisAlignedBoundingBox(Matrix4X4.Identity); Vector3 boundsCenter = (bounds.maxXYZ + bounds.minXYZ) / 2; - meshTransforms[index] *= Matrix4X4.CreateTranslation(new Vector3(0, 0, -boundsCenter.z + bounds.ZSize / 2)); + object3D.Matrix *= Matrix4X4.CreateTranslation(new Vector3(0, 0, -boundsCenter.z + bounds.ZSize / 2)); } - public static void PlaceMeshAtHeight(List meshesGroupList, List meshTransforms, int index, double zHeight) + public static void PlaceMeshAtHeight(IObject3D objectToMove, double zHeight) { - AxisAlignedBoundingBox bounds = GetAxisAlignedBoundingBox(meshesGroupList[index], meshTransforms[index]); - Vector3 boundsCenter = (bounds.maxXYZ + bounds.minXYZ) / 2; + AxisAlignedBoundingBox bounds = objectToMove.GetAxisAlignedBoundingBox(Matrix4X4.Identity); - meshTransforms[index] *= Matrix4X4.CreateTranslation(new Vector3(0, 0, zHeight - boundsCenter.z + bounds.ZSize / 2)); + objectToMove.Matrix *= Matrix4X4.CreateTranslation(new Vector3(0, 0, zHeight - bounds.minXYZ.z)); } public static void CenterMeshGroupXY(List meshesGroupList, List meshTransforms, int index) @@ -210,74 +214,50 @@ namespace MatterHackers.MatterControl meshTransforms[index] *= Matrix4X4.CreateTranslation(new Vector3(-boundsCenter.x + bounds.XSize / 2, -boundsCenter.y + bounds.YSize / 2, 0)); } - public static void FindPositionForGroupAndAddToPlate(MeshGroup meshGroupToAdd, Matrix4X4 meshTransform, List perMeshInfo, List meshesGroupsToAvoid, List meshTransforms) + public static void MoveToOpenPosition(IObject3D objectToAdd, IObject3D scene) { - if (meshGroupToAdd == null || meshGroupToAdd.Meshes.Count < 1) + if (objectToAdd == null || !scene.HasChildren) { return; } - // first find the bounds of what is already here. - AxisAlignedBoundingBox allPlacedMeshBounds = GetAxisAlignedBoundingBox(meshesGroupsToAvoid[0], meshTransforms[0]); - for (int i = 1; i < meshesGroupsToAvoid.Count; i++) - { - AxisAlignedBoundingBox nextMeshBounds = GetAxisAlignedBoundingBox(meshesGroupsToAvoid[i], meshTransforms[i]); - allPlacedMeshBounds = AxisAlignedBoundingBox.Union(allPlacedMeshBounds, nextMeshBounds); - } - - meshesGroupsToAvoid.Add(meshGroupToAdd); - - PlatingMeshGroupData newMeshInfo = new PlatingMeshGroupData(); - perMeshInfo.Add(newMeshInfo); - meshTransforms.Add(meshTransform); - - int meshGroupIndex = meshesGroupsToAvoid.Count - 1; - + // find the bounds of all items in the scene + AxisAlignedBoundingBox allPlacedMeshBounds = scene.Children.GetUnionedAxisAlignedBoundingBox(); + // move the part to the total bounds lower left side - MeshGroup meshGroup = meshesGroupsToAvoid[meshGroupIndex]; - Vector3 meshLowerLeft = GetAxisAlignedBoundingBox(meshGroup, meshTransforms[meshGroupIndex]).minXYZ; - meshTransforms[meshGroupIndex] *= Matrix4X4.CreateTranslation(-meshLowerLeft + allPlacedMeshBounds.minXYZ); + Vector3 meshLowerLeft = objectToAdd.GetAxisAlignedBoundingBox(Matrix4X4.Identity).minXYZ; + objectToAdd.Matrix *= Matrix4X4.CreateTranslation(-meshLowerLeft + allPlacedMeshBounds.minXYZ); - MoveMeshGroupToOpenPosition(meshGroupIndex, perMeshInfo, meshesGroupsToAvoid, meshTransforms); + // keep moving the item until its in an open slot + MoveToOpenPosition(objectToAdd, scene, allPlacedMeshBounds); - PlaceMeshGroupOnBed(meshesGroupsToAvoid, meshTransforms, meshGroupIndex); + //PlaceMeshGroupOnBed(objectToAdd); } - static AxisAlignedBoundingBox GetAxisAlignedBoundingBox(MeshGroup meshGroup, Matrix4X4 transform) + public static void MoveToOpenPosition(IObject3D itemToMove, IObject3D scene, AxisAlignedBoundingBox allPlacedMeshBounds) { - return meshGroup.GetAxisAlignedBoundingBox(transform); - } - - public static void MoveMeshGroupToOpenPosition(int meshGroupToMoveIndex, List perMeshInfo, List allMeshGroups, List meshTransforms) - { - AxisAlignedBoundingBox allPlacedMeshBounds = GetAxisAlignedBoundingBox(allMeshGroups[0], meshTransforms[0]); - for (int i = 1; i < meshGroupToMoveIndex; i++) - { - AxisAlignedBoundingBox nextMeshBounds = GetAxisAlignedBoundingBox(allMeshGroups[i], meshTransforms[i]); - allPlacedMeshBounds = AxisAlignedBoundingBox.Union(allPlacedMeshBounds, nextMeshBounds); - } - double xStart = allPlacedMeshBounds.minXYZ.x; double yStart = allPlacedMeshBounds.minXYZ.y; - MeshGroup meshGroupToMove = allMeshGroups[meshGroupToMoveIndex]; // find a place to put it that doesn't hit anything - AxisAlignedBoundingBox meshToMoveBounds = GetAxisAlignedBoundingBox(meshGroupToMove, meshTransforms[meshGroupToMoveIndex]); + AxisAlignedBoundingBox itemToMoveBounds = itemToMove.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + // add in a few mm so that it will not be touching - meshToMoveBounds.minXYZ -= new Vector3(2, 2, 0); - meshToMoveBounds.maxXYZ += new Vector3(2, 2, 0); + itemToMoveBounds.minXYZ -= new Vector3(2, 2, 0); + itemToMoveBounds.maxXYZ += new Vector3(2, 2, 0); Matrix4X4 transform = Matrix4X4.Identity; int currentSize = 1; bool partPlaced = false; - while (!partPlaced && meshGroupToMoveIndex > 0) + + while (!partPlaced && itemToMove != null) { int yStep = 0; int xStep = currentSize; // check far right edge for (yStep = 0; yStep < currentSize; yStep++) { - partPlaced = CheckPosition(meshGroupToMoveIndex, allMeshGroups, meshTransforms, meshGroupToMove, meshToMoveBounds, yStep, xStep, ref transform); + partPlaced = CheckPosition(scene, itemToMove, itemToMoveBounds, yStep, xStep, ref transform); if (partPlaced) { @@ -291,7 +271,7 @@ namespace MatterHackers.MatterControl // check top edge for (xStep = 0; xStep < currentSize; xStep++) { - partPlaced = CheckPosition(meshGroupToMoveIndex, allMeshGroups, meshTransforms, meshGroupToMove, meshToMoveBounds, yStep, xStep, ref transform); + partPlaced = CheckPosition(scene, itemToMove, itemToMoveBounds, yStep, xStep, ref transform); if (partPlaced) { @@ -303,49 +283,50 @@ namespace MatterHackers.MatterControl { xStep = currentSize; // check top right point - partPlaced = CheckPosition(meshGroupToMoveIndex, allMeshGroups, meshTransforms, meshGroupToMove, meshToMoveBounds, yStep, xStep, ref transform); + partPlaced = CheckPosition(scene, itemToMove, itemToMoveBounds, yStep, xStep, ref transform); } } currentSize++; } - meshTransforms[meshGroupToMoveIndex] *= transform; + itemToMove.Matrix *= transform; } - private static bool CheckPosition(int meshGroupToMoveIndex, List allMeshGroups, List meshTransforms, MeshGroup meshGroupToMove, AxisAlignedBoundingBox meshToMoveBounds, int yStep, int xStep, ref Matrix4X4 transform) + private static bool CheckPosition(IObject3D scene, IObject3D itemToMove, AxisAlignedBoundingBox meshToMoveBounds, int yStep, int xStep, ref Matrix4X4 transform) { double xStepAmount = 5; double yStepAmount = 5; Matrix4X4 positionTransform = Matrix4X4.CreateTranslation(xStep * xStepAmount, yStep * yStepAmount, 0); Vector3 newPosition = Vector3.Transform(Vector3.Zero, positionTransform); + transform = Matrix4X4.CreateTranslation(newPosition); + AxisAlignedBoundingBox testBounds = meshToMoveBounds.NewTransformed(transform); - bool foundHit = false; - for (int i = 0; i < meshGroupToMoveIndex; i++) + + foreach (IObject3D meshToTest in scene.Children) { - MeshGroup meshToTest = allMeshGroups[i]; - if (meshToTest != meshGroupToMove) + if (meshToTest != itemToMove) { - AxisAlignedBoundingBox existingMeshBounds = GetAxisAlignedBoundingBox(meshToTest, meshTransforms[i]); + AxisAlignedBoundingBox existingMeshBounds = meshToTest.GetAxisAlignedBoundingBox(Matrix4X4.Identity); AxisAlignedBoundingBox intersection = AxisAlignedBoundingBox.Intersection(testBounds, existingMeshBounds); if (intersection.XSize > 0 && intersection.YSize > 0) { - foundHit = true; - break; + return false; } } } - if (!foundHit) - { - return true; - } - - return false; + return true; } + static AxisAlignedBoundingBox GetAxisAlignedBoundingBox(MeshGroup meshGroup, Matrix4X4 transform) + { + return meshGroup.GetAxisAlignedBoundingBox(transform); + } + + /* public static void CreateITraceableForMeshGroup(List perMeshGroupInfo, List meshGroups, int meshGroupIndex, ReportProgressRatio reportProgress) { if (meshGroups != null) @@ -431,10 +412,11 @@ namespace MatterHackers.MatterControl return allPolys; } + */ - public static Matrix4X4 ApplyAtCenter(IHasAABB meshToApplyTo, Matrix4X4 currentTransform, Matrix4X4 transformToApply) + public static Matrix4X4 ApplyAtCenter(IObject3D object3DToApplayTo, Matrix4X4 transformToApply) { - return ApplyAtCenter(meshToApplyTo.GetAxisAlignedBoundingBox(currentTransform), currentTransform, transformToApply); + return ApplyAtCenter(object3DToApplayTo.GetAxisAlignedBoundingBox(Matrix4X4.Identity), object3DToApplayTo.Matrix, transformToApply); } public static Matrix4X4 ApplyAtCenter(AxisAlignedBoundingBox boundsToApplyTo, Matrix4X4 currentTransform, Matrix4X4 transformToApply) @@ -450,110 +432,4 @@ namespace MatterHackers.MatterControl return currentTransform; } } - - public class MeshFaceTraceable : IPrimitive - { - Face face; - public MeshFaceTraceable(Face face) - { - this.face = face; - } - - public RGBA_Floats GetColor(IntersectInfo info) { return RGBA_Floats.Red; } - - public MaterialAbstract Material { get { return null; } set { } } - - public bool GetContained(List results, AxisAlignedBoundingBox subRegion) - { - AxisAlignedBoundingBox bounds = GetAxisAlignedBoundingBox(); - if (bounds.Contains(subRegion)) - { - results.Add(this); - return true; - } - - return false; - } - - public IntersectInfo GetClosestIntersection(Ray ray) - { - // find the point on the plane - Vector3[] positions = new Vector3[3]; - int index = 0; - foreach (FaceEdge faceEdge in face.FaceEdges()) - { - positions[index++] = faceEdge.firstVertex.Position; - if(index==3) - { - break; - } - } - Plane plane = new Plane(positions[0], positions[1], positions[2]); - double distanceToHit; - bool hitFrontOfPlane; - if (plane.RayHitPlane(ray, out distanceToHit, out hitFrontOfPlane)) - { - Vector3 polyPlaneIntersection = ray.origin + ray.directionNormal * distanceToHit; - if (face.PointInPoly(polyPlaneIntersection)) - { - IntersectInfo info = new IntersectInfo(); - info.closestHitObject = this; - info.distanceToHit = distanceToHit; - info.hitPosition = polyPlaneIntersection; - info.normalAtHit = face.normal; - info.hitType = IntersectionType.FrontFace; - return info; - } - } - - return null; - } - - public int FindFirstRay(RayBundle rayBundle, int rayIndexToStartCheckingFrom) - { - throw new NotImplementedException(); - } - - public void GetClosestIntersections(RayBundle rayBundle, int rayIndexToStartCheckingFrom, IntersectInfo[] intersectionsForBundle) - { - throw new NotImplementedException(); - } - - public IEnumerable IntersectionIterator(Ray ray) - { - throw new NotImplementedException(); - } - - public double GetSurfaceArea() - { - AxisAlignedBoundingBox aabb = GetAxisAlignedBoundingBox(); - - double minDimension = Math.Min(aabb.XSize, Math.Min(aabb.YSize, aabb.ZSize)); - if(minDimension == aabb.XSize) - { - return aabb.YSize * aabb.ZSize; - } - else if(minDimension == aabb.YSize) - { - return aabb.XSize * aabb.ZSize; - } - - return aabb.XSize * aabb.YSize; - } - - public AxisAlignedBoundingBox GetAxisAlignedBoundingBox() - { - return face.GetAxisAlignedBoundingBox(); - } - - public Vector3 GetCenter() - { - return face.GetCenter(); - } - - public double GetIntersectCost() - { - return 700; - } - } } diff --git a/PartPreviewWindow/SaveAsWindow.cs b/PartPreviewWindow/SaveAsWindow.cs index 003d4dc34..678f31b92 100644 --- a/PartPreviewWindow/SaveAsWindow.cs +++ b/PartPreviewWindow/SaveAsWindow.cs @@ -15,13 +15,13 @@ namespace MatterHackers.MatterControl { public class SaveAsWindow : SystemWindow { - private Action functionToCallOnSaveAs; + private Action functionToCallOnSaveAs; private TextImageButtonFactory textImageButtonFactory = new TextImageButtonFactory(); private MHTextEditWidget textToAddWidget; LibrarySelectorWidget librarySelectorWidget; Button saveAsButton; - public SaveAsWindow(Action functionToCallOnSaveAs, List providerLocator, bool showQueue, bool getNewName) + public SaveAsWindow(Action functionToCallOnSaveAs, List providerLocator, bool showQueue, bool getNewName) : base(480, 500) { textImageButtonFactory.normalTextColor = ActiveTheme.Instance.PrimaryTextColor; @@ -30,10 +30,9 @@ namespace MatterHackers.MatterControl textImageButtonFactory.disabledTextColor = ActiveTheme.Instance.TabLabelUnselected; textImageButtonFactory.disabledFillColor = new RGBA_Bytes(); - Title = "MatterControl - " + "Save As".Localize(); AlwaysOnTopOfMain = true; + Title = "MatterControl - " + "Save As".Localize(); this.Name = "Save As Window"; - this.functionToCallOnSaveAs = functionToCallOnSaveAs; FlowLayoutWidget topToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom); @@ -41,32 +40,34 @@ namespace MatterHackers.MatterControl topToBottom.Padding = new BorderDouble(3, 0, 3, 5); // Creates Header - FlowLayoutWidget headerRow = new FlowLayoutWidget(FlowDirection.LeftToRight); - headerRow.HAnchor = HAnchor.ParentLeftRight; - headerRow.Margin = new BorderDouble(0, 3, 0, 0); - headerRow.Padding = new BorderDouble(0, 3, 0, 3); + FlowLayoutWidget headerRow = new FlowLayoutWidget(FlowDirection.LeftToRight) + { + HAnchor = HAnchor.ParentLeftRight, + Margin = new BorderDouble(0, 3, 0, 0), + Padding = new BorderDouble(0, 3, 0, 3) + }; + BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; //Creates Text and adds into header + TextWidget elementHeader = new TextWidget("Save New Design".Localize() + ":", pointSize: 14) { - string saveAsLabel = "Save New Design".Localize() + ":"; - TextWidget elementHeader = new TextWidget(saveAsLabel, pointSize: 14); - elementHeader.TextColor = ActiveTheme.Instance.PrimaryTextColor; - elementHeader.HAnchor = HAnchor.ParentLeftRight; - elementHeader.VAnchor = Agg.UI.VAnchor.ParentBottom; + TextColor = ActiveTheme.Instance.PrimaryTextColor, + HAnchor = HAnchor.ParentLeftRight, + VAnchor = Agg.UI.VAnchor.ParentBottom + }; - headerRow.AddChild(elementHeader); - topToBottom.AddChild(headerRow); - } + headerRow.AddChild(elementHeader); + topToBottom.AddChild(headerRow); //Creates container in the middle of window - FlowLayoutWidget middleRowContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); + FlowLayoutWidget middleRowContainer = new FlowLayoutWidget(FlowDirection.TopToBottom) { - middleRowContainer.HAnchor = HAnchor.ParentLeftRight; - middleRowContainer.VAnchor = VAnchor.ParentBottomTop; - middleRowContainer.Padding = new BorderDouble(5); - middleRowContainer.BackgroundColor = ActiveTheme.Instance.SecondaryBackgroundColor; - } + HAnchor = HAnchor.ParentLeftRight, + VAnchor = VAnchor.ParentBottomTop, + Padding = new BorderDouble(5), + BackgroundColor = ActiveTheme.Instance.SecondaryBackgroundColor + }; librarySelectorWidget = new LibrarySelectorWidget(showQueue); @@ -77,32 +78,34 @@ namespace MatterHackers.MatterControl librarySelectorWidget.ChangedCurrentLibraryProvider += breadCrumbWidget.SetBreadCrumbs; // put in the area to pick the provider to save to + // Adds text box and check box to the above container + GuiWidget chooseWindow = new GuiWidget(10, 30) { - //Adds text box and check box to the above container - GuiWidget chooseWindow = new GuiWidget(10, 30); - chooseWindow.HAnchor = HAnchor.ParentLeftRight; - chooseWindow.VAnchor = VAnchor.ParentBottomTop; - chooseWindow.Margin = new BorderDouble(5); - chooseWindow.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - chooseWindow.Padding = new BorderDouble(3); - chooseWindow.AddChild(librarySelectorWidget); - - middleRowContainer.AddChild(chooseWindow); - } + HAnchor = HAnchor.ParentLeftRight, + VAnchor = VAnchor.ParentBottomTop, + Margin = new BorderDouble(5), + BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor, + Padding = new BorderDouble(3), + }; + chooseWindow.AddChild(librarySelectorWidget); + middleRowContainer.AddChild(chooseWindow); // put in the area to type in the new name if(getNewName) { - string fileNameLabel = "Design Name".Localize(); - TextWidget fileNameHeader = new TextWidget(fileNameLabel, pointSize: 12); - fileNameHeader.TextColor = ActiveTheme.Instance.PrimaryTextColor; - fileNameHeader.Margin = new BorderDouble(5); - fileNameHeader.HAnchor = HAnchor.ParentLeft; + TextWidget fileNameHeader = new TextWidget("Design Name".Localize(), pointSize: 12) + { + TextColor = ActiveTheme.Instance.PrimaryTextColor, + Margin = new BorderDouble(5), + HAnchor = HAnchor.ParentLeft + }; //Adds text box and check box to the above container - textToAddWidget = new MHTextEditWidget("", pixelWidth: 300, messageWhenEmptyAndNotSelected: "Enter a Design Name Here".Localize()); - textToAddWidget.HAnchor = HAnchor.ParentLeftRight; - textToAddWidget.Margin = new BorderDouble(5); + textToAddWidget = new MHTextEditWidget("", pixelWidth: 300, messageWhenEmptyAndNotSelected: "Enter a Design Name Here".Localize()) + { + HAnchor = HAnchor.ParentLeftRight, + Margin = new BorderDouble(5) + }; textToAddWidget.ActualTextEditWidget.EnterPressed += new KeyEventHandler(ActualTextEditWidget_EnterPressed); middleRowContainer.AddChild(fileNameHeader); @@ -190,7 +193,8 @@ namespace MatterHackers.MatterControl string fileNameAndPath = Path.Combine(ApplicationDataStorage.Instance.ApplicationLibraryDataPath, fileName); SaveAsReturnInfo returnInfo = new SaveAsReturnInfo(newName, fileNameAndPath, librarySelectorWidget.CurrentLibraryProvider); - functionToCallOnSaveAs(returnInfo); + functionToCallOnSaveAs(returnInfo, null); + CloseOnIdle(); } } diff --git a/TextCreator/TextCreatorMainWindow.cs b/PartPreviewWindow/SelectedObjectPanel.cs similarity index 61% rename from TextCreator/TextCreatorMainWindow.cs rename to PartPreviewWindow/SelectedObjectPanel.cs index 44dcdf0a8..1c020425a 100644 --- a/TextCreator/TextCreatorMainWindow.cs +++ b/PartPreviewWindow/SelectedObjectPanel.cs @@ -1,5 +1,5 @@ /* -Copyright (c) 2014, Lars Brubaker +Copyright (c) 2014, Lars Brubaker, John Lewin All rights reserved. Redistribution and use in source and binary forms, with or without @@ -27,45 +27,39 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ +using MatterHackers.Agg; using MatterHackers.Agg.UI; -using MatterHackers.MatterControl.SlicerConfiguration; using MatterHackers.MeshVisualizer; using MatterHackers.VectorMath; +using System; +using System.IO; +using MatterHackers.Localizations; -namespace MatterHackers.MatterControl.Plugins.TextCreator +namespace MatterHackers.MatterControl.PartPreviewWindow { - public class TextCreatorMainWindow : SystemWindow + + public class SelectedObjectPanel : FlowLayoutWidget { - private View3DTextCreator part3DView; - - public TextCreatorMainWindow() - : base(690, 340) + public SelectedObjectPanel() : base(FlowDirection.TopToBottom) { - Title = "MatterControl: Text Creator"; + var buttonHeight = 40; - BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - - double buildHeight = ActiveSliceSettings.Instance.GetValue(SettingsKey.build_height); - - part3DView = new View3DTextCreator( - new Vector3(ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_size), buildHeight), - ActiveSliceSettings.Instance.GetValue(SettingsKey.print_center), - ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_shape)); - - this.AddChild(part3DView); - - this.AnchorAll(); - - part3DView.Closed += (sender, e) => + TextImageButtonFactory textImageButtonFactory = new TextImageButtonFactory() { - Close(); + normalTextColor = ActiveTheme.Instance.PrimaryTextColor, + hoverTextColor = ActiveTheme.Instance.PrimaryTextColor, + disabledTextColor = ActiveTheme.Instance.PrimaryTextColor, + pressedTextColor = ActiveTheme.Instance.PrimaryTextColor, + FixedHeight = buttonHeight, + FixedWidth = buttonHeight, + AllowThemeToAdjustImage = false, + checkedBorderColor = RGBA_Bytes.White }; - Width = 640; - Height = 480; + BackgroundColor = new RGBA_Bytes(0, 0, 0, 120); - ShowAsSystemWindow(); - MinimumSize = new Vector2(400, 300); + HAnchor |= HAnchor.ParentRight; + VAnchor = VAnchor.ParentTop | VAnchor.FitToChildren; } } } \ No newline at end of file diff --git a/PartPreviewWindow/View3D/DebugBvh.cs b/PartPreviewWindow/View3D/DebugBvh.cs index a8a8613f6..d35e9f452 100644 --- a/PartPreviewWindow/View3D/DebugBvh.cs +++ b/PartPreviewWindow/View3D/DebugBvh.cs @@ -36,6 +36,7 @@ using MatterHackers.RenderOpenGl; using MatterHackers.Agg; using System.Collections.Generic; using MatterHackers.RayTracer.Traceable; +using MatterHackers.DataConverters3D; namespace MatterHackers.MatterControl.PartPreviewWindow { @@ -70,13 +71,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow if (zBuffered) { - RenderMeshToGl.Render(lineMesh, RGBA_Bytes.Black, lineTransform, RenderTypes.Shaded); + GLHelper.Render(lineMesh, RGBA_Bytes.Black, lineTransform, RenderTypes.Shaded); //drawEvent.graphics2D.Line(cornerPositionScreen, cornerPositionCcwScreen, RGBA_Bytes.Gray); } else { // render on top of everything very lightly - RenderMeshToGl.Render(lineMesh, new RGBA_Bytes(RGBA_Bytes.Black, 5), lineTransform, RenderTypes.Shaded); + GLHelper.Render(lineMesh, new RGBA_Bytes(RGBA_Bytes.Black, 5), lineTransform, RenderTypes.Shaded); } } diff --git a/PartPreviewWindow/View3D/Gui3D/HeightValueDisplay.cs b/PartPreviewWindow/View3D/Gui3D/HeightValueDisplay.cs index 68abb555f..517ce3a77 100644 --- a/PartPreviewWindow/View3D/Gui3D/HeightValueDisplay.cs +++ b/PartPreviewWindow/View3D/Gui3D/HeightValueDisplay.cs @@ -66,10 +66,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow Vector2 startLineSelectionPos = Vector2.Zero; Vector2 midLinePos = Vector2.Zero; - if (MeshViewerToDrawWith.HaveSelection) + if (MeshViewerToDrawWith.Scene.HasSelection) { // draw the hight from the bottom to the bed - AxisAlignedBoundingBox selectedBounds = MeshViewerToDrawWith.GetBoundsForSelection(); + AxisAlignedBoundingBox selectedBounds = MeshViewerToDrawWith.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); Vector2 screenPosition = new Vector2(-100, 0); Vector3[] bottomPoints = new Vector3[4]; @@ -95,7 +95,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow OriginRelativeParent = screenPosition; // draw the line that is on the ground - double yGround = Math.Round(startLineGroundPos.y) + .5; + double yGround = (int)(startLineGroundPos.y + .5) + .5; drawEvent.graphics2D.Line(startLineGroundPos.x, yGround, startLineGroundPos.x + HorizontalLineLength - 5, yGround, RGBA_Bytes.Black); // and the line that is at the base of the selection double ySelection = Math.Round(startLineSelectionPos.y) + .5; diff --git a/PartPreviewWindow/View3D/Gui3D/SelectionShadow.cs b/PartPreviewWindow/View3D/Gui3D/SelectionShadow.cs index 1100803bd..7f95f6598 100644 --- a/PartPreviewWindow/View3D/Gui3D/SelectionShadow.cs +++ b/PartPreviewWindow/View3D/Gui3D/SelectionShadow.cs @@ -28,16 +28,12 @@ either expressed or implied, of the FreeBSD Project. */ using MatterHackers.Agg; -using MatterHackers.Agg.PlatformAbstract; +using MatterHackers.DataConverters3D; using MatterHackers.MeshVisualizer; using MatterHackers.PolygonMesh; -using MatterHackers.PolygonMesh.Processors; -using MatterHackers.RayTracer; using MatterHackers.RenderOpenGl; using MatterHackers.VectorMath; using System; -using System.Collections.Generic; -using System.IO; namespace MatterHackers.MatterControl.PartPreviewWindow { @@ -51,9 +47,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow this.view3DWidget = view3DWidget; } - public override void SetPosition() + public override void SetPosition(IObject3D selectedItem) { - AxisAlignedBoundingBox selectedBounds = MeshViewerToDrawWith.GetBoundsForSelection(); + AxisAlignedBoundingBox selectedBounds = selectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); Vector3 boundsCenter = selectedBounds.Center; TotalTransform = Matrix4X4.CreateTranslation(new Vector3(boundsCenter.x, boundsCenter.y, 0.1)); @@ -61,13 +57,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public override void DrawGlContent(EventArgs e) { - if (MeshViewerToDrawWith.SelectedMeshGroup != null) + if (MeshViewerToDrawWith.Scene.HasSelection) { // draw the bounds on the bed - AxisAlignedBoundingBox selectedBounds = MeshViewerToDrawWith.GetBoundsForSelection(); + AxisAlignedBoundingBox selectedBounds = MeshViewerToDrawWith.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); Mesh bottomBounds = PlatonicSolids.CreateCube(selectedBounds.XSize, selectedBounds.YSize, .1); - RenderMeshToGl.Render(bottomBounds, new RGBA_Bytes(22, 80, 220, 30), TotalTransform, RenderTypes.Shaded); + GLHelper.Render(bottomBounds, new RGBA_Bytes(22, 80, 220, 30), TotalTransform, RenderTypes.Shaded); } base.DrawGlContent(e); diff --git a/PartPreviewWindow/View3D/Gui3D/SnapingIndicator.cs b/PartPreviewWindow/View3D/Gui3D/SnapingIndicator.cs index 35e25f9a0..5ba761f76 100644 --- a/PartPreviewWindow/View3D/Gui3D/SnapingIndicator.cs +++ b/PartPreviewWindow/View3D/Gui3D/SnapingIndicator.cs @@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project. using MatterHackers.Agg; using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.MeshVisualizer; using MatterHackers.VectorMath; @@ -49,75 +50,74 @@ namespace MatterHackers.MatterControl.PartPreviewWindow MeshViewerToDrawWith.AfterDraw += MeshViewerToDrawWith_Draw; } - public override void SetPosition() + public override void SetPosition(IObject3D selectedItem) { - if (MeshViewerToDrawWith.HaveSelection) + // draw the hight from the bottom to the bed + AxisAlignedBoundingBox selectedBounds = selectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + + MeshSelectInfo meshSelectInfo = view3DWidget.CurrentSelectInfo; + + var trackballWidget = MeshViewerToDrawWith.TrackballTumbleWidget; + + switch (meshSelectInfo.HitQuadrant) { - // draw the hight from the bottom to the bed - AxisAlignedBoundingBox selectedBounds = MeshViewerToDrawWith.GetBoundsForSelection(); + case HitQuadrant.LB: + { + Vector3 cornerPoint = new Vector3(selectedBounds.minXYZ.x, selectedBounds.minXYZ.y, 0); + double distBetweenPixelsWorldSpace = trackballWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); - MeshSelectInfo meshSelectInfo = view3DWidget.CurrentSelectInfo; + lines[0] = trackballWidget.GetScreenPosition(cornerPoint - new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); + lines[1] = trackballWidget.GetScreenPosition(cornerPoint - new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); - switch (meshSelectInfo.HitQuadrant) - { - case HitQuadrant.LB: - { - Vector3 cornerPoint = new Vector3(selectedBounds.minXYZ.x, selectedBounds.minXYZ.y, 0); - double distBetweenPixelsWorldSpace = MeshViewerToDrawWith.TrackballTumbleWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); + lines[2] = trackballWidget.GetScreenPosition(cornerPoint - new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); + lines[3] = trackballWidget.GetScreenPosition(cornerPoint - new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); + } + break; - lines[0] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); - lines[1] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); + case HitQuadrant.LT: + { + Vector3 cornerPoint = new Vector3(selectedBounds.minXYZ.x, selectedBounds.maxXYZ.y, 0); + double distBetweenPixelsWorldSpace = trackballWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); - lines[2] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); - lines[3] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); - } - break; + lines[0] = trackballWidget.GetScreenPosition(cornerPoint - new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); + lines[1] = trackballWidget.GetScreenPosition(cornerPoint - new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); - case HitQuadrant.LT: - { - Vector3 cornerPoint = new Vector3(selectedBounds.minXYZ.x, selectedBounds.maxXYZ.y, 0); - double distBetweenPixelsWorldSpace = MeshViewerToDrawWith.TrackballTumbleWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); + lines[2] = trackballWidget.GetScreenPosition(cornerPoint + new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); + lines[3] = trackballWidget.GetScreenPosition(cornerPoint + new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); + } + break; - lines[0] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); - lines[1] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); + case HitQuadrant.RB: + { + Vector3 cornerPoint = new Vector3(selectedBounds.maxXYZ.x, selectedBounds.minXYZ.y, 0); + double distBetweenPixelsWorldSpace = trackballWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); - lines[2] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); - lines[3] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); - } - break; + lines[0] = trackballWidget.GetScreenPosition(cornerPoint + new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); + lines[1] = trackballWidget.GetScreenPosition(cornerPoint + new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); - case HitQuadrant.RB: - { - Vector3 cornerPoint = new Vector3(selectedBounds.maxXYZ.x, selectedBounds.minXYZ.y, 0); - double distBetweenPixelsWorldSpace = MeshViewerToDrawWith.TrackballTumbleWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); + lines[2] = trackballWidget.GetScreenPosition(cornerPoint - new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); + lines[3] = trackballWidget.GetScreenPosition(cornerPoint - new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); + } + break; - lines[0] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); - lines[1] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); + case HitQuadrant.RT: + { + Vector3 cornerPoint = new Vector3(selectedBounds.maxXYZ.x, selectedBounds.maxXYZ.y, 0); + double distBetweenPixelsWorldSpace = trackballWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); - lines[2] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); - lines[3] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); - } - break; + lines[0] = trackballWidget.GetScreenPosition(cornerPoint + new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); + lines[1] = trackballWidget.GetScreenPosition(cornerPoint + new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); - case HitQuadrant.RT: - { - Vector3 cornerPoint = new Vector3(selectedBounds.maxXYZ.x, selectedBounds.maxXYZ.y, 0); - double distBetweenPixelsWorldSpace = MeshViewerToDrawWith.TrackballTumbleWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); - - lines[0] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); - lines[1] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); - - lines[2] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); - lines[3] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); - } - break; - } + lines[2] = trackballWidget.GetScreenPosition(cornerPoint + new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); + lines[3] = trackballWidget.GetScreenPosition(cornerPoint + new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); + } + break; } } private void MeshViewerToDrawWith_Draw(object drawingWidget, DrawEventArgs drawEvent) { - if (MeshViewerToDrawWith.SelectedMeshGroup != null + if (MeshViewerToDrawWith.Scene.HasSelection && view3DWidget.meshViewerWidget.SnapGridDistance > 0 && view3DWidget.CurrentSelectInfo.DownOnPart) { diff --git a/PartPreviewWindow/View3D/Gui3D/UpArrow3D.cs b/PartPreviewWindow/View3D/Gui3D/UpArrow3D.cs index 81b3ea323..947f9f2ba 100644 --- a/PartPreviewWindow/View3D/Gui3D/UpArrow3D.cs +++ b/PartPreviewWindow/View3D/Gui3D/UpArrow3D.cs @@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project. using MatterHackers.Agg; using MatterHackers.Agg.PlatformAbstract; +using MatterHackers.DataConverters3D; using MatterHackers.MeshVisualizer; using MatterHackers.PolygonMesh; using MatterHackers.PolygonMesh.Processors; @@ -47,10 +48,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private PlaneShape hitPlane; private Vector3 lastMoveDelta; private Matrix4X4 transformOnMouseDown = Matrix4X4.Identity; - private Mesh upArrow; + + private static IObject3D upArrowItem = null; + private View3DWidget view3DWidget; private double zHitHeight; - + public UpArrow3D(View3DWidget view3DWidget) : base(null, view3DWidget.meshViewerWidget) { @@ -60,23 +63,17 @@ namespace MatterHackers.MatterControl.PartPreviewWindow DrawOnTop = true; this.view3DWidget = view3DWidget; - string arrowFile = Path.Combine("Icons", "3D Icons", "up_pointer.stl"); - if (StaticData.Instance.FileExists(arrowFile)) - { - using (Stream staticDataStream = StaticData.Instance.OpenSteam(arrowFile)) - { - using (MemoryStream arrowStream = new MemoryStream()) - { - staticDataStream.CopyTo(arrowStream, 1 << 16); - List loadedMeshGroups = MeshFileIo.Load(arrowStream, Path.GetExtension(arrowFile)); - upArrow = loadedMeshGroups[0].Meshes[0]; - CollisionVolume = PlatingHelper.CreateTraceDataForMesh(upArrow); - //CollisionVolume = new CylinderShape(arrowBounds.XSize / 2, arrowBounds.ZSize, new SolidMaterial(RGBA_Floats.Red, .5, 0, .4)); - //CollisionVolume = new CylinderShape(arrowBounds.XSize / 2 * 4, arrowBounds.ZSize * 4, new SolidMaterial(RGBA_Floats.Red, .5, 0, .4)); - } + if (upArrowItem == null) + { + string arrowFile = Path.Combine("Icons", "3D Icons", "up_pointer.stl"); + using (Stream arrowStream = StaticData.Instance.OpenSteam(arrowFile)) + { + upArrowItem = MeshFileIo.Load(arrowStream, Path.GetExtension(arrowFile)); } } + + CollisionVolume = upArrowItem.TraceData(); } public override void DrawGlContent(EventArgs e) @@ -87,16 +84,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { shouldDrawScaleControls = false; } - if (MeshViewerToDrawWith.SelectedMeshGroup != null + if (MeshViewerToDrawWith.Scene.HasSelection && shouldDrawScaleControls) { if (MouseOver) { - RenderMeshToGl.Render(upArrow, RGBA_Bytes.Red, TotalTransform, RenderTypes.Shaded); + GLHelper.Render(upArrowItem.Mesh, RGBA_Bytes.Red, TotalTransform, RenderTypes.Shaded); } else { - RenderMeshToGl.Render(upArrow, RGBA_Bytes.Black, TotalTransform, RenderTypes.Shaded); + GLHelper.Render(upArrowItem.Mesh, RGBA_Bytes.Black, TotalTransform, RenderTypes.Shaded); } } @@ -112,7 +109,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow IntersectInfo info = hitPlane.GetClosestIntersection(mouseEvent3D.MouseRay); zHitHeight = info.hitPosition.z; - transformOnMouseDown = MeshViewerToDrawWith.SelectedMeshGroupTransform; + + var selectedItem = MeshViewerToDrawWith.Scene.SelectedItem; + if (selectedItem != null) + { + transformOnMouseDown = selectedItem.Matrix; + } base.OnMouseDown(mouseEvent3D); } @@ -121,18 +123,19 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { IntersectInfo info = hitPlane.GetClosestIntersection(mouseEvent3D.MouseRay); - if (info != null && MeshViewerToDrawWith.SelectedMeshGroupIndex != -1) + if (info != null && MeshViewerToDrawWith.Scene.HasSelection) { + var selectedItem = MeshViewerToDrawWith.Scene.SelectedItem; Vector3 delta = new Vector3(0, 0, info.hitPosition.z - zHitHeight); // move it back to where it started - MeshViewerToDrawWith.SelectedMeshGroupTransform *= Matrix4X4.CreateTranslation(new Vector3(-lastMoveDelta)); + selectedItem.Matrix *= Matrix4X4.CreateTranslation(new Vector3(-lastMoveDelta)); if (MeshViewerToDrawWith.SnapGridDistance > 0) { // snap this position to the grid double snapGridDistance = MeshViewerToDrawWith.SnapGridDistance; - AxisAlignedBoundingBox selectedBounds = MeshViewerToDrawWith.GetBoundsForSelection(); + AxisAlignedBoundingBox selectedBounds = selectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); // snap the z position double bottom = selectedBounds.minXYZ.z + delta.z; @@ -141,7 +144,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } // and move it from there to where we are now - MeshViewerToDrawWith.SelectedMeshGroupTransform *= Matrix4X4.CreateTranslation(new Vector3(delta)); + selectedItem.Matrix *= Matrix4X4.CreateTranslation(new Vector3(delta)); lastMoveDelta = delta; @@ -158,9 +161,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow base.OnMouseUp(mouseEvent3D); } - public override void SetPosition() + public override void SetPosition(IObject3D selectedItem) { - AxisAlignedBoundingBox selectedBounds = MeshViewerToDrawWith.GetBoundsForSelection(); + AxisAlignedBoundingBox selectedBounds = selectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); Vector3 boundsCenter = selectedBounds.Center; Vector3 centerTop = new Vector3(boundsCenter.x, boundsCenter.y, selectedBounds.maxXYZ.z); diff --git a/BrailleBuilder/BrailleBuilderMainWindow.cs b/PartPreviewWindow/View3D/IObject3DEditor.cs similarity index 58% rename from BrailleBuilder/BrailleBuilderMainWindow.cs rename to PartPreviewWindow/View3D/IObject3DEditor.cs index c69fc2960..90546fda7 100644 --- a/BrailleBuilder/BrailleBuilderMainWindow.cs +++ b/PartPreviewWindow/View3D/IObject3DEditor.cs @@ -1,5 +1,5 @@ /* -Copyright (c) 2014, Lars Brubaker +Copyright (c) 2016, Lars Brubaker, John Lewin All rights reserved. Redistribution and use in source and binary forms, with or without @@ -26,46 +26,19 @@ 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. */ +//#define DoBooleanTest using MatterHackers.Agg.UI; -using MatterHackers.MatterControl.SlicerConfiguration; -using MatterHackers.MeshVisualizer; -using MatterHackers.VectorMath; +using MatterHackers.DataConverters3D; +using System; +using System.Collections.Generic; -namespace MatterHackers.MatterControl.Plugins.BrailleBuilder +namespace MatterHackers.MatterControl.PartPreviewWindow { - public class BrailleBuilderMainWindow : SystemWindow + public interface IObject3DEditor { - private View3DBrailleBuilder part3DView; - - public BrailleBuilderMainWindow() - : base(690, 340) - { - Title = "MatterControl: Braille Builder"; - - BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - - double buildHeight = ActiveSliceSettings.Instance.GetValue(SettingsKey.build_height); - - part3DView = new View3DBrailleBuilder( - new Vector3(ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_size), buildHeight), - ActiveSliceSettings.Instance.GetValue(SettingsKey.print_center), - ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_shape)); - - this.AddChild(part3DView); - - this.AnchorAll(); - - part3DView.Closed += (sender, e) => - { - Close(); - }; - - Width = 640; - Height = 480; - - ShowAsSystemWindow(); - MinimumSize = new Vector2(400, 300); - } + string Name { get; } + IEnumerable SupportedTypes(); + GuiWidget Create(IObject3D item, View3DWidget parentView3D); } } \ No newline at end of file diff --git a/PartPreviewWindow/View3D/SideBar/MirrorControls.cs b/PartPreviewWindow/View3D/SideBar/MirrorControls.cs index 67e830cd4..be6d5bde8 100644 --- a/PartPreviewWindow/View3D/SideBar/MirrorControls.cs +++ b/PartPreviewWindow/View3D/SideBar/MirrorControls.cs @@ -26,8 +26,6 @@ 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. */ -//#define DoBooleanTest - using MatterHackers.Agg; using MatterHackers.Agg.ImageProcessing; using MatterHackers.Agg.PlatformAbstract; @@ -36,6 +34,7 @@ using MatterHackers.Localizations; using MatterHackers.VectorMath; using System; using System.Collections.Generic; +using System.Diagnostics; namespace MatterHackers.MatterControl.PartPreviewWindow { @@ -85,9 +84,17 @@ namespace MatterHackers.MatterControl.PartPreviewWindow mirrorControls.Add(mirrorXButton); mirrorXButton.Click += (s, e) => { - if (view3DWidget.SelectedMeshGroupIndex != -1) + if (view3DWidget.Scene.HasSelection) { view3DWidget.UndoBuffer.AddAndDo(new UndoRedoActions(() => MirrorOnAxis(0), () => MirrorOnAxis(0))); + + Debugger.Break(); + /* TODO: Revise above for scenebundle with the following... + var selectedItem = view3DWidget.Scene.SelectedItem; + selectedItem.Mesh.ReverseFaceEdges(); + selectedItem.Matrix = PlatingHelper.ApplyAtCenter(selectedItem, Matrix4X4.CreateScale(-1, 1, 1)); + view3DWidget.PartHasBeenChanged(); + Invalidate(); */ } }; @@ -96,9 +103,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow mirrorControls.Add(mirrorYButton); mirrorYButton.Click += (s, e) => { - if (view3DWidget.SelectedMeshGroupIndex != -1) + if (view3DWidget.Scene.HasSelection) { view3DWidget.UndoBuffer.AddAndDo(new UndoRedoActions(() => MirrorOnAxis(1), () => MirrorOnAxis(1))); + Debugger.Break(); + /* TODO: Revise above for scenebundle with the following... + var selectedItem = view3DWidget.Scene.SelectedItem; + selectedItem.Mesh.ReverseFaceEdges(); + selectedItem.Matrix = PlatingHelper.ApplyAtCenter(selectedItem, Matrix4X4.CreateScale(1, -1, 1)); + view3DWidget.PartHasBeenChanged(); + Invalidate(); */ } }; @@ -107,9 +121,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow mirrorControls.Add(mirrorZButton); mirrorZButton.Click += (s, e) => { - if (view3DWidget.SelectedMeshGroupIndex != -1) + if (view3DWidget.Scene.HasSelection) { view3DWidget.UndoBuffer.AddAndDo(new UndoRedoActions(() => MirrorOnAxis(2), () => MirrorOnAxis(2))); + Debugger.Break(); + /* TODO: Revise above for scenebundle with the following... + var selectedItem = view3DWidget.Scene.SelectedItem; + selectedItem.Mesh.ReverseFaceEdges(); + selectedItem.Matrix = PlatingHelper.ApplyAtCenter(selectedItem, Matrix4X4.CreateScale(1, 1, -1)); + view3DWidget.PartHasBeenChanged(); + Invalidate(); */ } }; buttonPanel.AddChild(buttonContainer); @@ -119,11 +140,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private void MirrorOnAxis(int axisIndex) { + /* TODO: Revise for scen_bundle view3DWidget.SelectedMeshGroup.ReverseFaceEdges(); Vector3 mirorAxis = Vector3.One; mirorAxis[axisIndex] = -1; view3DWidget.SelectedMeshGroupTransform = PlatingHelper.ApplyAtCenter(view3DWidget.SelectedMeshGroup, view3DWidget.SelectedMeshGroupTransform, Matrix4X4.CreateScale(mirorAxis)); - view3DWidget.PartHasBeenChanged(); + view3DWidget.PartHasBeenChanged(); */ Invalidate(); } diff --git a/PartPreviewWindow/View3D/SideBar/ScaleControls.cs b/PartPreviewWindow/View3D/SideBar/ScaleControls.cs index 0ba4d1769..f55a157bf 100644 --- a/PartPreviewWindow/View3D/SideBar/ScaleControls.cs +++ b/PartPreviewWindow/View3D/SideBar/ScaleControls.cs @@ -26,7 +26,6 @@ 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. */ -//#define DoBooleanTest using MatterHackers.Agg; using MatterHackers.Agg.ImageProcessing; @@ -150,15 +149,21 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private void ApplyScaleFromEditField() { - if (view3DWidget.HaveSelection) + if (view3DWidget.Scene.HasSelection) { - Matrix4X4 startingTransform = view3DWidget.SelectedMeshGroupTransform; + Matrix4X4 startingTransform = view3DWidget.Scene.SelectedItem.Matrix; + Vector3 currentScale = view3DWidget.Scene.SelectedItem.ExtraData.CurrentScale; double scale = scaleRatioControl.ActuallNumberEdit.Value; if (scale > 0) { ScaleAxis(scale, 0); + + view3DWidget.Scene.SelectedItem.ExtraData.CurrentScale.y = currentScale.y; + view3DWidget.Scene.SelectedItem.ExtraData.CurrentScale.z = currentScale.z; ScaleAxis(scale, 1); + + view3DWidget.Scene.SelectedItem.ExtraData.CurrentScale.z = currentScale.z; ScaleAxis(scale, 2); } @@ -178,11 +183,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow sizeDisplay[axisIndex] = new EditableNumberDisplay(view3DWidget.textImageButtonFactory, "100", "1000.00"); sizeDisplay[axisIndex].EditComplete += (sender, e) => { - if (view3DWidget.HaveSelection) + if (view3DWidget.Scene.HasSelection) { - Matrix4X4 startingTransform = view3DWidget.SelectedMeshGroupTransform; + Matrix4X4 startingTransform = view3DWidget.Scene.SelectedItem.Matrix; SetNewModelSize(sizeDisplay[axisIndex].GetValue(), axisIndex); - sizeDisplay[axisIndex].SetDisplayString("{0:0.00}".FormatWith(view3DWidget.SelectedMeshGroup.GetAxisAlignedBoundingBox().Size[axisIndex])); + sizeDisplay[axisIndex].SetDisplayString("{0:0.00}".FormatWith(view3DWidget.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity).Size[axisIndex])); OnSelectedTransformChanged(null, null); view3DWidget.AddUndoForSelectedMeshGroupTransform(startingTransform); } @@ -260,31 +265,39 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private void ScaleAxis(double scaleIn, int axis) { - AxisAlignedBoundingBox originalMeshBounds = view3DWidget.SelectedMeshGroup.GetAxisAlignedBoundingBox(); + var selectedItem = view3DWidget.Scene.SelectedItem; + AxisAlignedBoundingBox originalMeshBounds = selectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); - Vector3 newScale = Vector3.One; + AxisAlignedBoundingBox scaledBounds = selectedItem.GetAxisAlignedBoundingBox(selectedItem.Matrix); + + // first we remove any scale we have applied and then scale to the new value + Vector3 axisRemoveScalings = Vector3.One; + if(originalMeshBounds.XSize > 0 && scaledBounds.XSize > 0) axisRemoveScalings.x = originalMeshBounds.XSize / scaledBounds.XSize; + if (originalMeshBounds.YSize > 0 && scaledBounds.YSize > 0) axisRemoveScalings.y = originalMeshBounds.YSize / scaledBounds.YSize; + if (originalMeshBounds.ZSize > 0 && scaledBounds.ZSize > 0) axisRemoveScalings.z = originalMeshBounds.ZSize / scaledBounds.ZSize; + + Matrix4X4 removeScaleMatrix = Matrix4X4.CreateScale(axisRemoveScalings); + + Vector3 newScale = selectedItem.ExtraData.CurrentScale; newScale[axis] = scaleIn; Matrix4X4 totalScale = Matrix4X4.CreateScale(newScale); - view3DWidget.SelectedMeshGroupTransform = PlatingHelper.ApplyAtCenter(view3DWidget.SelectedMeshGroup, view3DWidget.SelectedMeshGroupTransform, totalScale); + selectedItem.Matrix = PlatingHelper.ApplyAtCenter(selectedItem, totalScale); - // keep the bottom where it was - AxisAlignedBoundingBox scaledBounds = view3DWidget.SelectedMeshGroup.GetAxisAlignedBoundingBox(view3DWidget.SelectedMeshGroupTransform); - PlatingHelper.PlaceMeshAtHeight(view3DWidget.MeshGroups, view3DWidget.MeshGroupTransforms, view3DWidget.SelectedMeshGroupIndex, scaledBounds.minXYZ.z); - - PlatingHelper.PlaceMeshGroupOnBed(view3DWidget.MeshGroups, view3DWidget.MeshGroupTransforms, view3DWidget.SelectedMeshGroupIndex); + PlatingHelper.PlaceMeshAtHeight(selectedItem, originalMeshBounds.minXYZ.z); view3DWidget.PartHasBeenChanged(); Invalidate(); + view3DWidget.Scene.SelectedItem.ExtraData.CurrentScale[axis] = scaleIn; OnSelectedTransformChanged(this, null); } private void SetNewModelSize(double sizeInMm, int axis) { - if (view3DWidget.HaveSelection) + if (view3DWidget.Scene.HasSelection) { // because we remove any current scale before we change to a new one we only get the size of the base mesh data - AxisAlignedBoundingBox originalMeshBounds = view3DWidget.SelectedMeshGroup.GetAxisAlignedBoundingBox(view3DWidget.SelectedMeshGroupTransform); + AxisAlignedBoundingBox originalMeshBounds = view3DWidget.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); double currentSize = originalMeshBounds.Size[axis]; double desiredSize = sizeDisplay[axis].GetValue(); @@ -309,20 +322,26 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private void OnSelectedTransformChanged(object sender, EventArgs e) { if (sizeDisplay[0] != null - && view3DWidget.SelectedMeshGroup != null) + && view3DWidget.Scene.HasSelection) { - AxisAlignedBoundingBox bounds = view3DWidget.SelectedMeshGroup.GetAxisAlignedBoundingBox(view3DWidget.SelectedMeshGroupTransform); + var selectedItem = view3DWidget.Scene.SelectedItem; + + // TODO: jlewin - could be this simple but how do we call old/new transform values from this context given they've likely been updated and we track one value + // AxisAlignedBoundingBox bounds = view3DWidget.SelectedObject3D.GetAxisAlignedBoundingBox(); + AxisAlignedBoundingBox bounds = selectedItem.GetAxisAlignedBoundingBox(selectedItem.Matrix); sizeDisplay[0].SetDisplayString("{0:0.00}".FormatWith(bounds.Size[0])); sizeDisplay[1].SetDisplayString("{0:0.00}".FormatWith(bounds.Size[1])); sizeDisplay[2].SetDisplayString("{0:0.00}".FormatWith(bounds.Size[2])); // set the scaling to be this new size - AxisAlignedBoundingBox originalMeshBounds = view3DWidget.SelectedMeshGroup.GetAxisAlignedBoundingBox(); - AxisAlignedBoundingBox scaledBounds = view3DWidget.SelectedMeshGroup.GetAxisAlignedBoundingBox(view3DWidget.SelectedMeshGroupTransform); + AxisAlignedBoundingBox originalMeshBounds = selectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + AxisAlignedBoundingBox scaledBounds = selectedItem.GetAxisAlignedBoundingBox(selectedItem.Matrix); Vector3 currentScale = new Vector3(); currentScale.x = scaledBounds.XSize / originalMeshBounds.XSize; currentScale.y = scaledBounds.YSize / originalMeshBounds.YSize; currentScale.z = scaledBounds.ZSize / originalMeshBounds.ZSize; + + selectedItem.ExtraData.CurrentScale = currentScale; } else { diff --git a/PartPreviewWindow/View3D/SideBar/View3DWidgetSidebar.cs b/PartPreviewWindow/View3D/SideBar/View3DWidgetSidebar.cs new file mode 100644 index 000000000..2bea9fd30 --- /dev/null +++ b/PartPreviewWindow/View3D/SideBar/View3DWidgetSidebar.cs @@ -0,0 +1,482 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg; +using MatterHackers.Agg.Image; +using MatterHackers.Agg.PlatformAbstract; +using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; +using MatterHackers.Localizations; +using MatterHackers.MatterControl.DataStorage; +using MatterHackers.MatterControl.SlicerConfiguration; +using MatterHackers.PolygonMesh; +using MatterHackers.PolygonMesh.Processors; +using MatterHackers.RayTracer; +using MatterHackers.RenderOpenGl; +using MatterHackers.VectorMath; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace MatterHackers.MatterControl.PartPreviewWindow +{ + public class View3DWidgetSidebar : FlowLayoutWidget + { + private static string iconPath = Path.Combine("Icons", "3D Icons"); + private static string applicationUserDataPath = ApplicationDataStorage.ApplicationUserDataPath; + private static string createdIconPath = Path.Combine(applicationUserDataPath, "data", "temp", "shape thumbnails"); + + private View3DWidget view3DWidget; + + public CheckBox expandMaterialOptions { get; private set; } + public CheckBox expandRotateOptions { get; private set; } + public CheckBox expandViewOptions { get; private set; } + + public FlowLayoutWidget rotateOptionContainer; + private FlowLayoutWidget viewOptionContainer; + private FlowLayoutWidget materialOptionContainer; + + // TODO: Remove debugging variables and draw functions once drag items are positioning correctly + private Vector2 mouseMovePosition; + private RectangleDouble meshViewerPosition; + private FlowLayoutWidget buttonPanel; + + public View3DWidgetSidebar(View3DWidget view3DWidget, double buildHeight, UndoBuffer undoBuffer) + : base(FlowDirection.TopToBottom) + { + this.view3DWidget = view3DWidget; + this.Width = 200; + + var ExpandMenuOptionFactory = view3DWidget.ExpandMenuOptionFactory; + // put in undo redo + { + FlowLayoutWidget undoRedoButtons = new FlowLayoutWidget() + { + VAnchor = VAnchor.FitToChildren | VAnchor.ParentTop, + HAnchor = HAnchor.FitToChildren | HAnchor.ParentCenter, + }; + + var WhiteButtonFactory = view3DWidget.WhiteButtonFactory; + + double oldWidth = WhiteButtonFactory.FixedWidth; + WhiteButtonFactory.FixedWidth = WhiteButtonFactory.FixedWidth / 2; + Button undoButton = WhiteButtonFactory.Generate("Undo".Localize(), centerText: true); + undoButton.Name = "3D View Undo"; + undoButton.Enabled = false; + undoButton.Click += (sender, e) => + { + undoBuffer.Undo(); + }; + undoRedoButtons.AddChild(undoButton); + + Button redoButton = WhiteButtonFactory.Generate("Redo".Localize(), centerText: true); + redoButton.Name = "3D View Redo"; + redoButton.Enabled = false; + redoButton.Click += (sender, e) => + { + undoBuffer.Redo(); + }; + undoRedoButtons.AddChild(redoButton); + this.AddChild(undoRedoButtons); + + undoBuffer.Changed += (sender, e) => + { + undoButton.Enabled = undoBuffer.UndoCount > 0; + redoButton.Enabled = undoBuffer.RedoCount > 0; + }; + WhiteButtonFactory.FixedWidth = oldWidth; + } + + buttonPanel = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + HAnchor = HAnchor.ParentLeftRight, + VAnchor = VAnchor.FitToChildren + }; + this.AddChild(buttonPanel); + + { + BorderDouble buttonMargin = new BorderDouble(top: 3); + + expandRotateOptions = ExpandMenuOptionFactory.GenerateCheckBoxButton("Rotate".Localize().ToUpper(), + View3DWidget.ArrowRight, + View3DWidget.ArrowDown); + expandRotateOptions.Margin = new BorderDouble(bottom: 2); + expandRotateOptions.CheckedStateChanged += expandRotateOptions_CheckedStateChanged; + + buttonPanel.AddChild(expandRotateOptions); + + rotateOptionContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); + rotateOptionContainer.HAnchor = HAnchor.ParentLeftRight; + rotateOptionContainer.Visible = false; + buttonPanel.AddChild(rotateOptionContainer); + + buttonPanel.AddChild(new ScaleControls(view3DWidget)); + + buttonPanel.AddChild(new MirrorControls(view3DWidget)); + + // put in the material options + int numberOfExtruders = ActiveSliceSettings.Instance.GetValue(SettingsKey.extruder_count); + + expandMaterialOptions = ExpandMenuOptionFactory.GenerateCheckBoxButton( + "Materials".Localize().ToUpper(), + View3DWidget.ArrowRight, + View3DWidget.ArrowDown); + expandMaterialOptions.Margin = new BorderDouble(bottom: 2); + expandMaterialOptions.CheckedStateChanged += expandMaterialOptions_CheckedStateChanged; + + if (numberOfExtruders > 1) + { + buttonPanel.AddChild(expandMaterialOptions); + + materialOptionContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); + materialOptionContainer.HAnchor = HAnchor.ParentLeftRight; + materialOptionContainer.Visible = false; + + buttonPanel.AddChild(materialOptionContainer); + view3DWidget.AddMaterialControls(materialOptionContainer); + } + + // put in the view options + { + expandViewOptions = ExpandMenuOptionFactory.GenerateCheckBoxButton("Display".Localize().ToUpper(), + View3DWidget.ArrowRight, + View3DWidget.ArrowDown); + expandViewOptions.Margin = new BorderDouble(bottom: 2); + buttonPanel.AddChild(expandViewOptions); + expandViewOptions.CheckedStateChanged += expandViewOptions_CheckedStateChanged; + + viewOptionContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); + viewOptionContainer.HAnchor = HAnchor.ParentLeftRight; + viewOptionContainer.Padding = new BorderDouble(left: 4); + viewOptionContainer.Visible = false; + { + CheckBox showBedCheckBox = new CheckBox("Show Print Bed".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); + showBedCheckBox.Checked = true; + showBedCheckBox.CheckedStateChanged += (sender, e) => + { + view3DWidget.meshViewerWidget.RenderBed = showBedCheckBox.Checked; + }; + viewOptionContainer.AddChild(showBedCheckBox); + + if (buildHeight > 0) + { + CheckBox showBuildVolumeCheckBox = new CheckBox("Show Print Area".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); + showBuildVolumeCheckBox.Checked = false; + showBuildVolumeCheckBox.Margin = new BorderDouble(bottom: 5); + showBuildVolumeCheckBox.CheckedStateChanged += (sender, e) => + { + view3DWidget.meshViewerWidget.RenderBuildVolume = showBuildVolumeCheckBox.Checked; + }; + viewOptionContainer.AddChild(showBuildVolumeCheckBox); + } + + if (UserSettings.Instance.IsTouchScreen) + { + UserSettings.Instance.set("defaultRenderSetting", RenderTypes.Shaded.ToString()); + } + else + { + view3DWidget.CreateRenderTypeRadioButtons(viewOptionContainer); + } + } + buttonPanel.AddChild(viewOptionContainer); + } + + // Add vertical spacer + this.AddChild(new GuiWidget() + { + VAnchor = VAnchor.ParentBottomTop + }); + + AddGridSnapSettings(this); + } + + this.Padding = new BorderDouble(6, 6); + this.Margin = new BorderDouble(0, 1); + this.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; + this.VAnchor = VAnchor.ParentBottomTop; + } + + + // InitializeComponent is called after the Sidebar property has been assigned as SidebarPlugins + // are passed an instance of the View3DWidget and expect to be able to access the Sidebar to + // call create button methods + public void InitializeComponents() + { + PluginFinder SideBarPlugins = new PluginFinder(); + foreach (SideBarPlugin plugin in SideBarPlugins.Plugins) + { + buttonPanel.AddChild(plugin.CreateSideBarTool(view3DWidget)); + } + + HashSet mappedEditors; + + var objectEditorsByType = new Dictionary>(); + + // TODO: Consider only loading once into a static + var objectEditors = new PluginFinder().Plugins; + foreach (IObject3DEditor editor in objectEditors) + { + foreach (Type type in editor.SupportedTypes()) + { + if (!objectEditorsByType.TryGetValue(type, out mappedEditors)) + { + mappedEditors = new HashSet(); + objectEditorsByType.Add(type, mappedEditors); + } + + mappedEditors.Add(editor); + } + } + + view3DWidget.objectEditors = objectEditors; + view3DWidget.objectEditorsByType = objectEditorsByType; + } + + private void expandMaterialOptions_CheckedStateChanged(object sender, EventArgs e) + { + if (expandMaterialOptions.Checked == true) + { + expandRotateOptions.Checked = false; + expandViewOptions.Checked = false; + } + materialOptionContainer.Visible = expandMaterialOptions.Checked; + } + + private void expandRotateOptions_CheckedStateChanged(object sender, EventArgs e) + { + if (rotateOptionContainer.Visible != expandRotateOptions.Checked) + { + if (expandRotateOptions.Checked == true) + { + expandViewOptions.Checked = false; + expandMaterialOptions.Checked = false; + } + rotateOptionContainer.Visible = expandRotateOptions.Checked; + } + } + + private void expandViewOptions_CheckedStateChanged(object sender, EventArgs e) + { + if (viewOptionContainer.Visible != expandViewOptions.Checked) + { + if (expandViewOptions.Checked == true) + { + expandRotateOptions.Checked = false; + expandMaterialOptions.Checked = false; + } + viewOptionContainer.Visible = expandViewOptions.Checked; + } + } + + private void AddGridSnapSettings(GuiWidget widgetToAddTo) + { + FlowLayoutWidget container = new FlowLayoutWidget() + { + Margin = new BorderDouble(5, 0) * GuiWidget.DeviceScale, + }; + + TextWidget snapGridLabel = new TextWidget("Snap Grid".Localize()) + { + TextColor = ActiveTheme.Instance.PrimaryTextColor, + VAnchor = VAnchor.ParentCenter, + Margin = new BorderDouble(3, 0, 0, 0) * GuiWidget.DeviceScale, + }; + + container.AddChild(snapGridLabel); + + var selectableOptions = new DropDownList("Custom", Direction.Up) + { + VAnchor = VAnchor.ParentCenter | VAnchor.FitToChildren, + }; + + Dictionary snapSettings = new Dictionary() + { + { 0, "Off" }, + { .1, "0.1" }, + { .25, "0.25" }, + { .5, "0.5" }, + { 1, "1" }, + { 2, "2" }, + { 5, "5" }, + }; + + foreach (KeyValuePair snapSetting in snapSettings) + { + double valueLocal = snapSetting.Key; + + MenuItem newItem = selectableOptions.AddItem(snapSetting.Value); + if (view3DWidget.meshViewerWidget.SnapGridDistance == valueLocal) + { + selectableOptions.SelectedLabel = snapSetting.Value; + } + + newItem.Selected += (sender, e) => + { + view3DWidget.meshViewerWidget.SnapGridDistance = snapSetting.Key; + }; + } + + container.AddChild(selectableOptions); + + widgetToAddTo.AddChild(container); + } + + public GuiWidget CreateAddButton(string buttonLable, string iconFileName, Func createMeshFunction) + { + string iconPathAndFileName = Path.Combine(iconPath, iconFileName); + ImageBuffer buttonImage = new ImageBuffer(64, 64, 32, new BlenderBGRA()); + if (StaticData.Instance.FileExists(iconPathAndFileName)) + { + buttonImage = StaticData.Instance.LoadImage(iconPathAndFileName); + buttonImage.SetRecieveBlender(new BlenderPreMultBGRA()); + buttonImage = ImageBuffer.CreateScaledImage(buttonImage, 64, 64); + } + else + { + iconPathAndFileName = Path.Combine(createdIconPath, iconFileName); + if (File.Exists(iconPathAndFileName)) + { + ImageIO.LoadImageData(iconPathAndFileName, buttonImage); + buttonImage.SetRecieveBlender(new BlenderPreMultBGRA()); + } + else + { + Task.Run(() => + { + IObject3D item = createMeshFunction(); + + // If the item has an empty mesh but children, flatten them into a mesh and swap the new item into place + if (item.Mesh == null && item.HasChildren) + { + item = new Object3D() + { + ItemType = Object3DTypes.Model, + Mesh = MeshFileIo.DoMerge(item.ToMeshGroupList(), new MeshOutputSettings()) + }; + } + + if (item.Mesh != null) + { + item.Mesh.Triangulate(); + + ThumbnailTracer tracer = new ThumbnailTracer(item, 64, 64); + tracer.DoTrace(); + + buttonImage.SetRecieveBlender(new BlenderPreMultBGRA()); + //buttonImage = ImageBuffer.CreateScaledImage(tracer.destImage, 64, 64); + buttonImage.CopyFrom(tracer.destImage); + UiThread.RunOnIdle(() => + { + if (!Directory.Exists(createdIconPath)) + { + Directory.CreateDirectory(createdIconPath); + } + ImageIO.SaveImageData(iconPathAndFileName, buttonImage); + }); + } + }); + } + } + + var textColor = ActiveTheme.Instance.PrimaryTextColor; + GuiWidget addItemButton = CreateButtonState(buttonLable, buttonImage, ActiveTheme.Instance.PrimaryBackgroundColor, textColor); + + addItemButton.Margin = new BorderDouble(3); + addItemButton.MouseDown += (sender, e) => + { + view3DWidget.DragDropSource = createMeshFunction(); + }; + + addItemButton.MouseMove += (sender, mouseArgs) => + { + var screenSpaceMousePosition = addItemButton.TransformToScreenSpace(mouseArgs.Position); + view3DWidget.AltDragOver(screenSpaceMousePosition); + }; + + addItemButton.MouseUp += (sender, mouseArgs) => + { + if (addItemButton.LocalBounds.Contains(mouseArgs.Position) && view3DWidget.DragDropSource != null) + { + // Button click within the bounds of this control - Insert item at the best open position + PlatingHelper.MoveToOpenPosition(view3DWidget.DragDropSource, view3DWidget.Scene); + view3DWidget.InsertNewItem(view3DWidget.DragDropSource); + } + else if (view3DWidget.DragDropSource != null && view3DWidget.Scene.Children.Contains(view3DWidget.DragDropSource)) + { + // Drag release outside the bounds of this control and not within the scene - Remove inserted item + // + // Mouse and widget positions + var screenSpaceMousePosition = addItemButton.TransformToScreenSpace(mouseArgs.Position); + meshViewerPosition = this.view3DWidget.meshViewerWidget.TransformToScreenSpace(view3DWidget.meshViewerWidget.LocalBounds); + + // If the mouse is not within the meshViewer, remove the inserted drag item + if (!meshViewerPosition.Contains(screenSpaceMousePosition)) + { + view3DWidget.Scene.ModifyChildren(children => children.Remove(view3DWidget.DragDropSource)); + view3DWidget.Scene.ClearSelection(); + } + else + { + // Create and push the undo operation + view3DWidget.AddUndoOperation( + new InsertCommand(view3DWidget, view3DWidget.DragDropSource)); + } + } + + view3DWidget.DragDropSource = null; + }; + + return addItemButton; + } + + private static FlowLayoutWidget CreateButtonState(string buttonLabel, ImageBuffer buttonImage, RGBA_Bytes color, RGBA_Bytes textColor) + { + FlowLayoutWidget flowLayout = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + BackgroundColor = color, + }; + flowLayout.AddChild(new ImageWidget(buttonImage) + { + Margin = new BorderDouble(0, 5, 0, 0), + BackgroundColor = RGBA_Bytes.Gray, + HAnchor = HAnchor.ParentCenter, + Selectable = false, + }); + flowLayout.AddChild(new TextWidget(buttonLabel, 0, 0, 9, Agg.Font.Justification.Center, textColor) + { + HAnchor = HAnchor.ParentCenter, + Selectable = false, + }); + return flowLayout; + } + } +} \ No newline at end of file diff --git a/PartPreviewWindow/View3D/UndoCommands/CopyUndoCommand.cs b/PartPreviewWindow/View3D/UndoCommands/CopyUndoCommand.cs index d28c3c425..6ac9d87a3 100644 --- a/PartPreviewWindow/View3D/UndoCommands/CopyUndoCommand.cs +++ b/PartPreviewWindow/View3D/UndoCommands/CopyUndoCommand.cs @@ -1,6 +1,7 @@ using MatterHackers.Agg.UI; using MatterHackers.PolygonMesh; using MatterHackers.VectorMath; +using System.Linq; namespace MatterHackers.MatterControl.PartPreviewWindow { @@ -8,39 +9,37 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { private int newItemIndex; private View3DWidget view3DWidget; - private Matrix4X4 newItemTransform; - PlatingMeshGroupData newItemPlatingData; - MeshGroup meshGroupThatWasDeleted; + IObject3D addedObject3D; + + bool wasLastItem; public CopyUndoCommand(View3DWidget view3DWidget, int newItemIndex) { this.view3DWidget = view3DWidget; this.newItemIndex = newItemIndex; - meshGroupThatWasDeleted = view3DWidget.MeshGroups[newItemIndex]; - newItemTransform = view3DWidget.MeshGroupTransforms[newItemIndex]; - newItemPlatingData = view3DWidget.MeshGroupExtraData[newItemIndex]; + + addedObject3D = view3DWidget.Scene.Children[newItemIndex]; + + wasLastItem = view3DWidget.Scene.Children.Last() == addedObject3D; } public void Undo() { - view3DWidget.MeshGroups.RemoveAt(newItemIndex); - view3DWidget.MeshGroupExtraData.RemoveAt(newItemIndex); - view3DWidget.MeshGroupTransforms.RemoveAt(newItemIndex); - if(view3DWidget.SelectedMeshGroupIndex >= view3DWidget.MeshGroups.Count) + view3DWidget.Scene.Children.RemoveAt(newItemIndex); + + if (wasLastItem) { - view3DWidget.SelectedMeshGroupIndex = view3DWidget.MeshGroups.Count - 1; + view3DWidget.Scene.SelectLastChild(); } view3DWidget.PartHasBeenChanged(); } public void Do() { - view3DWidget.MeshGroups.Insert(newItemIndex, meshGroupThatWasDeleted); - view3DWidget.MeshGroupTransforms.Insert(newItemIndex, newItemTransform); - view3DWidget.MeshGroupExtraData.Insert(newItemIndex, newItemPlatingData); + view3DWidget.Scene.Children.Insert(newItemIndex, addedObject3D); view3DWidget.Invalidate(); - view3DWidget.SelectedMeshGroupIndex = view3DWidget.MeshGroups.Count - 1; + view3DWidget.Scene.SelectLastChild(); } } } \ No newline at end of file diff --git a/PartPreviewWindow/View3D/UndoCommands/DeleteUndoCommand.cs b/PartPreviewWindow/View3D/UndoCommands/DeleteUndoCommand.cs index 3e77ba3b1..364b9386d 100644 --- a/PartPreviewWindow/View3D/UndoCommands/DeleteUndoCommand.cs +++ b/PartPreviewWindow/View3D/UndoCommands/DeleteUndoCommand.cs @@ -1,46 +1,71 @@ -using MatterHackers.Agg.UI; -using MatterHackers.PolygonMesh; -using MatterHackers.VectorMath; +/* +Copyright (c) 2016, 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 MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; namespace MatterHackers.MatterControl.PartPreviewWindow { - internal class DeleteUndoCommand : IUndoRedoCommand + public class DeleteCommand : IUndoRedoCommand { - private int deletedIndex; + private IObject3D item; + private View3DWidget view3DWidget; - private Matrix4X4 deletedTransform; - PlatingMeshGroupData deletedPlatingData; - MeshGroup meshGroupThatWasDeleted; - - public DeleteUndoCommand(View3DWidget view3DWidget, int deletedIndex) + public DeleteCommand(View3DWidget view3DWidget, IObject3D deletingItem) { this.view3DWidget = view3DWidget; - this.deletedIndex = deletedIndex; - meshGroupThatWasDeleted = view3DWidget.MeshGroups[deletedIndex]; - deletedTransform = view3DWidget.MeshGroupTransforms[deletedIndex]; - deletedPlatingData = view3DWidget.MeshGroupExtraData[deletedIndex]; + this.item = deletingItem; } public void Do() { - view3DWidget.MeshGroups.RemoveAt(deletedIndex); - view3DWidget.MeshGroupExtraData.RemoveAt(deletedIndex); - view3DWidget.MeshGroupTransforms.RemoveAt(deletedIndex); - if (view3DWidget.SelectedMeshGroupIndex >= view3DWidget.MeshGroups.Count) + view3DWidget.Scene.ModifyChildren(children => { - view3DWidget.SelectedMeshGroupIndex = view3DWidget.MeshGroups.Count - 1; - } + children.Remove(item); + }); + + view3DWidget.Scene.SelectLastChild(); + view3DWidget.PartHasBeenChanged(); } public void Undo() { - view3DWidget.MeshGroups.Insert(deletedIndex, meshGroupThatWasDeleted); - view3DWidget.MeshGroupTransforms.Insert(deletedIndex, deletedTransform); - view3DWidget.MeshGroupExtraData.Insert(deletedIndex, deletedPlatingData); - view3DWidget.Invalidate(); - view3DWidget.SelectedMeshGroupIndex = view3DWidget.MeshGroups.Count - 1; + view3DWidget.Scene.ModifyChildren(children => + { + children.Add(item); + }); + + view3DWidget.Scene.Select(item); + + view3DWidget.PartHasBeenChanged(); } } } \ No newline at end of file diff --git a/PartPreviewWindow/View3D/UndoCommands/GroupCommand.cs b/PartPreviewWindow/View3D/UndoCommands/GroupCommand.cs new file mode 100644 index 000000000..085437b21 --- /dev/null +++ b/PartPreviewWindow/View3D/UndoCommands/GroupCommand.cs @@ -0,0 +1,117 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; +using MatterHackers.PolygonMesh; + +namespace MatterHackers.MatterControl.PartPreviewWindow +{ + public class GroupCommand : IUndoRedoCommand + { + private IObject3D item; + private View3DWidget view3DWidget; + + public GroupCommand(View3DWidget view3DWidget, IObject3D selectedItem) + { + this.view3DWidget = view3DWidget; + this.item = selectedItem; + + if(view3DWidget.Scene.SelectedItem == selectedItem) + { + view3DWidget.Scene.ClearSelection(); + } + } + + public void Do() + { + if (view3DWidget.Scene.Children.Contains(item)) + { + // This is the original do() case. The selection group exists in the scene and must be flattened into a new grouped + var flattenedGroup = new Object3D + { + ItemType = Object3DTypes.Group + }; + + item.CollapseInto(flattenedGroup.Children, Object3DTypes.SelectionGroup); + + view3DWidget.Scene.ModifyChildren(children => + { + children.Remove(item); + children.Add(flattenedGroup); + }); + + // Update the local reference after flattening to make the redo pattern work + item = flattenedGroup; + + view3DWidget.Scene.Select(flattenedGroup); + } + else + { + // This the undo -> redo() case. The original Selection group has been collapsed and we need to rebuild it + view3DWidget.Scene.ModifyChildren(children => + { + // Remove all children from the scene + foreach (var child in item.Children) + { + children.Remove(child); + } + + // Add the item + children.Add(item); + }); + + view3DWidget.Scene.Select(item); + } + + view3DWidget.PartHasBeenChanged(); + } + + public void Undo() + { + if (!view3DWidget.Scene.Children.Contains(item)) + { + return; + } + + view3DWidget.Scene.ModifyChildren(children => + { + // Remove the group + children.Remove(item); + + // Add all children from the group + children.AddRange(item.Children); + }); + + view3DWidget.Scene.SelectLastChild(); + + view3DWidget.PartHasBeenChanged(); + } + } +} \ No newline at end of file diff --git a/PartPreviewWindow/View3D/UndoCommands/InsertCommand.cs b/PartPreviewWindow/View3D/UndoCommands/InsertCommand.cs new file mode 100644 index 000000000..0a69f4b57 --- /dev/null +++ b/PartPreviewWindow/View3D/UndoCommands/InsertCommand.cs @@ -0,0 +1,121 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; +using MatterHackers.PolygonMesh; +using MatterHackers.VectorMath; +using System.Linq; + +namespace MatterHackers.MatterControl.PartPreviewWindow +{ + public class InsertCommand : IUndoRedoCommand + { + private IObject3D item; + private Matrix4X4 originalTransform; + private View3DWidget view3DWidget; + + bool firstPass = true; + + public InsertCommand(View3DWidget view3DWidget, IObject3D insertingItem) + { + this.view3DWidget = view3DWidget; + this.item = insertingItem; + this.originalTransform = insertingItem.Matrix; + } + + public void Do() + { + if (!firstPass) + { + item.Matrix = originalTransform; + firstPass = false; + } + + view3DWidget.Scene.ModifyChildren(children => + { + children.Add(item); + }); + + view3DWidget.Scene.Select(item); + + view3DWidget.PartHasBeenChanged(); + } + + public void Undo() + { + view3DWidget.Scene.ModifyChildren(children => + { + children.Remove(item); + }); + + view3DWidget.Scene.SelectLastChild(); + + view3DWidget.PartHasBeenChanged(); + } + } + /* + internal class CopyUndoCommand : IUndoRedoCommand + { + private int newItemIndex; + private View3DWidget view3DWidget; + + IObject3D addedObject3D; + + bool wasLastItem; + + public CopyUndoCommand(View3DWidget view3DWidget, int newItemIndex) + { + this.view3DWidget = view3DWidget; + this.newItemIndex = newItemIndex; + + addedObject3D = view3DWidget.Scene.Children[newItemIndex]; + + wasLastItem = view3DWidget.Scene.Children.Last() == addedObject3D; + } + + public void Undo() + { + view3DWidget.Scene.Children.RemoveAt(newItemIndex); + + if (wasLastItem) + { + view3DWidget.Scene.SelectLastChild(); + } + view3DWidget.PartHasBeenChanged(); + } + + public void Do() + { + view3DWidget.Scene.Children.Insert(newItemIndex, addedObject3D); + view3DWidget.Invalidate(); + view3DWidget.Scene.SelectLastChild(); + } + } */ +} \ No newline at end of file diff --git a/PartPreviewWindow/View3D/UndoCommands/TransformUndoCommand.cs b/PartPreviewWindow/View3D/UndoCommands/TransformUndoCommand.cs index 5b5098e8e..6b34b537b 100644 --- a/PartPreviewWindow/View3D/UndoCommands/TransformUndoCommand.cs +++ b/PartPreviewWindow/View3D/UndoCommands/TransformUndoCommand.cs @@ -1,4 +1,34 @@ -using MatterHackers.Agg.UI; +/* +Copyright (c) 2016, 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 MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.PolygonMesh; using MatterHackers.VectorMath; @@ -6,27 +36,27 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { internal class TransformUndoCommand : IUndoRedoCommand { - private int meshGroupIndex; + private IObject3D transformedObject; private Matrix4X4 redoTransform; private Matrix4X4 undoTransform; private View3DWidget view3DWidget; - public TransformUndoCommand(View3DWidget view3DWidget, int meshGroupIndex, Matrix4X4 undoTransform, Matrix4X4 redoTransform) + public TransformUndoCommand(View3DWidget view3DWidget, IObject3D transformedObject, Matrix4X4 undoTransform, Matrix4X4 redoTransform) { this.view3DWidget = view3DWidget; - this.meshGroupIndex = meshGroupIndex; + this.transformedObject = transformedObject; this.undoTransform = undoTransform; this.redoTransform = redoTransform; } public void Do() { - view3DWidget.MeshGroupTransforms[meshGroupIndex] = redoTransform; + transformedObject.Matrix = redoTransform; } public void Undo() { - view3DWidget.MeshGroupTransforms[meshGroupIndex] = undoTransform; + transformedObject.Matrix = undoTransform; } } } \ No newline at end of file diff --git a/TextCreator/TextCreator.cs b/PartPreviewWindow/View3D/UndoCommands/UngroupCommand.cs similarity index 62% rename from TextCreator/TextCreator.cs rename to PartPreviewWindow/View3D/UndoCommands/UngroupCommand.cs index a32494f41..443c6e63e 100644 --- a/TextCreator/TextCreator.cs +++ b/PartPreviewWindow/View3D/UndoCommands/UngroupCommand.cs @@ -1,5 +1,5 @@ /* -Copyright (c) 2014, Lars Brubaker +Copyright (c) 2016, Lars Brubaker, John Lewin All rights reserved. Redistribution and use in source and binary forms, with or without @@ -28,34 +28,27 @@ either expressed or implied, of the FreeBSD Project. */ using MatterHackers.Agg.UI; -using MatterHackers.Localizations; -using MatterHackers.MatterControl.CreatorPlugins; -using MatterHackers.MatterControl.PluginSystem; -using System; +using MatterHackers.DataConverters3D; -namespace MatterHackers.MatterControl.Plugins.TextCreator +namespace MatterHackers.MatterControl.PartPreviewWindow { - public class TextCreatorPlugin : MatterControlPlugin + public class UngroupCommand : IUndoRedoCommand { - public override void Initialize(GuiWidget application) - { - var information = new CreatorInformation( - () => new TextCreatorMainWindow(), - "TC_32x32.png", - "Text Creator".Localize()); + private GroupCommand groupCommand; - RegisteredCreators.Instance.RegisterLaunchFunction(information); + public UngroupCommand(View3DWidget view3DWidget, IObject3D ungroupingItem) + { + this.groupCommand = new GroupCommand(view3DWidget, ungroupingItem); } - public override string GetPluginInfoJSon() + public void Do() { - return "{" + - "\"Name\": \"Text Creator\"," + - "\"UUID\": \"fbd06000-66c3-11e3-949a-0800200c9a66\"," + - "\"About\": \"A Creator that allows you to type in text and have it turned into printable extrusions.\"," + - "\"Developer\": \"MatterHackers, Inc.\"," + - "\"URL\": \"https://www.matterhackers.com\"" + - "}"; + groupCommand.Undo(); + } + + public void Undo() + { + groupCommand.Do(); } } } \ No newline at end of file diff --git a/PartPreviewWindow/View3D/View3DAlign.cs b/PartPreviewWindow/View3D/View3DAlign.cs index 8e791ec33..3fb9844f1 100644 --- a/PartPreviewWindow/View3D/View3DAlign.cs +++ b/PartPreviewWindow/View3D/View3DAlign.cs @@ -27,12 +27,14 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ +using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MeshVisualizer; using MatterHackers.PolygonMesh; using MatterHackers.VectorMath; using System.ComponentModel; using System.Globalization; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -42,29 +44,27 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { private void AlignSelected() { - if (SelectedMeshGroupIndex == -1) + if(Scene.HasSelection) { - SelectedMeshGroupIndex = 0; + Scene.SelectFirstChild(); } + // make sure our thread translates numbers correctly (always do this in a thread) Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - // save our data so we don't mess up the display while doing work - PushMeshGroupDataToAsynchLists(TraceInfoOpperation.DO_COPY); - // try to move all the not selected meshes relative to the selected mesh - AxisAlignedBoundingBox selectedOriginalBounds = asyncMeshGroups[SelectedMeshGroupIndex].GetAxisAlignedBoundingBox(); + AxisAlignedBoundingBox selectedOriginalBounds = Scene.SelectedItem.Mesh.GetAxisAlignedBoundingBox(); Vector3 selectedOriginalCenter = selectedOriginalBounds.Center; - AxisAlignedBoundingBox selectedCurrentBounds = asyncMeshGroups[SelectedMeshGroupIndex].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[SelectedMeshGroupIndex]); + AxisAlignedBoundingBox selectedCurrentBounds = Scene.SelectedItem.Mesh.GetAxisAlignedBoundingBox(Scene.SelectedItem.Matrix); Vector3 selctedCurrentCenter = selectedCurrentBounds.Center; - for (int meshGroupToMoveIndex = 0; meshGroupToMoveIndex < asyncMeshGroups.Count; meshGroupToMoveIndex++) + for (int meshGroupToMoveIndex = 0; meshGroupToMoveIndex < Scene.Children.Count; meshGroupToMoveIndex++) { - MeshGroup meshGroupToMove = asyncMeshGroups[meshGroupToMoveIndex]; - if (meshGroupToMove != asyncMeshGroups[SelectedMeshGroupIndex]) + IObject3D item = Scene.Children[meshGroupToMoveIndex]; + if (item != Scene.SelectedItem) { - AxisAlignedBoundingBox groupToMoveOriginalBounds = meshGroupToMove.GetAxisAlignedBoundingBox(); + AxisAlignedBoundingBox groupToMoveOriginalBounds = item.GetAxisAlignedBoundingBox(Matrix4X4.Identity); Vector3 groupToMoveOriginalCenter = groupToMoveOriginalBounds.Center; - AxisAlignedBoundingBox groupToMoveBounds = meshGroupToMove.GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[meshGroupToMoveIndex]); + AxisAlignedBoundingBox groupToMoveBounds = item.GetAxisAlignedBoundingBox(Scene.Children[meshGroupToMoveIndex].Matrix); Vector3 groupToMoveCenter = groupToMoveBounds.Center; Vector3 originalCoordinatesDelta = groupToMoveOriginalCenter - selectedOriginalCenter; @@ -74,54 +74,54 @@ namespace MatterHackers.MatterControl.PartPreviewWindow if (deltaRequired.Length > .0001) { - asyncMeshGroupTransforms[meshGroupToMoveIndex] *= Matrix4X4.CreateTranslation(deltaRequired); + Scene.Children[meshGroupToMoveIndex].Matrix *= Matrix4X4.CreateTranslation(deltaRequired); PartHasBeenChanged(); } } } + /* TODO: Align needs reconsidered // now put all the meshes into just one group - MeshGroup meshGroupWeAreKeeping = asyncMeshGroups[SelectedMeshGroupIndex]; - for (int meshGroupToMoveIndex = asyncMeshGroups.Count - 1; meshGroupToMoveIndex >= 0; meshGroupToMoveIndex--) + IObject3D itemWeAreKeeping = Scene.SelectedItem; + for (int meshGroupToMoveIndex = Scene.Children.Count - 1; meshGroupToMoveIndex >= 0; meshGroupToMoveIndex--) { - MeshGroup meshGroupToMove = asyncMeshGroups[meshGroupToMoveIndex]; - if (meshGroupToMove != meshGroupWeAreKeeping) + IObject3D itemToMove = Scene.Children[meshGroupToMoveIndex]; + if (itemToMove != itemWeAreKeeping) { // move all the meshes into the new aligned mesh group - for (int moveIndex = 0; moveIndex < meshGroupToMove.Meshes.Count; moveIndex++) + for (int moveIndex = 0; moveIndex < itemToMove.Meshes.Count; moveIndex++) { - Mesh mesh = meshGroupToMove.Meshes[moveIndex]; - meshGroupWeAreKeeping.Meshes.Add(mesh); + Mesh mesh = itemToMove.Meshes[moveIndex]; + itemWeAreKeeping.Meshes.Add(mesh); } - asyncMeshGroups.RemoveAt(meshGroupToMoveIndex); - asyncMeshGroupTransforms.RemoveAt(meshGroupToMoveIndex); + Scene.Children.RemoveAt(meshGroupToMoveIndex); + + // TODO: ******************** !!!!!!!!!!!!!!! ******************** + //asyncMeshGroupTransforms.RemoveAt(meshGroupToMoveIndex); } } + */ - asyncPlatingDatas.Clear(); - double ratioPerMeshGroup = 1.0 / asyncMeshGroups.Count; + // TODO: ******************** !!!!!!!!!!!!!!! ******************** + /* + double ratioPerMeshGroup = 1.0 / MeshGroups.Count; double currentRatioDone = 0; - for (int i = 0; i < asyncMeshGroups.Count; i++) + for (int i = 0; i < MeshGroups.Count; i++) { - PlatingMeshGroupData newInfo = new PlatingMeshGroupData(); - asyncPlatingDatas.Add(newInfo); - - MeshGroup meshGroup = asyncMeshGroups[i]; - // create the selection info - PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, i, (double progress0To1, string processingState, out bool continueProcessing) => + PlatingHelper.CreateITraceableForMeshGroup(MeshGroups, i, (double progress0To1, string processingState, out bool continueProcessing) => { ReportProgressChanged(progress0To1, processingState, out continueProcessing); }); currentRatioDone += ratioPerMeshGroup; - } + } */ } private async void AlignToSelectedMeshGroup() { - if (MeshGroups.Count > 0) + if (Scene.HasChildren) { // set the progress label text processingProgressControl.PercentComplete = 0; @@ -140,11 +140,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow return; } - // remove the original mesh and replace it with these new meshes - PullMeshGroupDataFromAsynchLists(); - // our selection changed to the mesh we just added which is at the end - SelectedMeshGroupIndex = MeshGroups.Count - 1; + Scene.SelectLastChild(); UnlockEditControls(); diff --git a/PartPreviewWindow/View3D/View3DAutoArange.cs b/PartPreviewWindow/View3D/View3DAutoArange.cs index 56f8532a4..1bc3ae525 100644 --- a/PartPreviewWindow/View3D/View3DAutoArange.cs +++ b/PartPreviewWindow/View3D/View3DAutoArange.cs @@ -28,29 +28,22 @@ either expressed or implied, of the FreeBSD Project. */ using MatterHackers.Agg.UI; -using MatterHackers.Localizations; -using MatterHackers.MatterControl.SlicerConfiguration; -using MatterHackers.MeshVisualizer; -using MatterHackers.PolygonMesh; +using MatterHackers.DataConverters3D; using MatterHackers.VectorMath; -using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.Threading; using System.Threading.Tasks; namespace MatterHackers.MatterControl.PartPreviewWindow { internal class ArangeUndoCommand : IUndoRedoCommand { - List allUndoTransforms = new List(); + private List allUndoTransforms = new List(); public ArangeUndoCommand(View3DWidget view3DWidget, List preArrangeTarnsforms, List postArrangeTarnsforms) { - for(int i=0; i 0) + // TODO: ******************** !!!!!!!!!!!!!!! ******************** + var arrangedScene = new Object3D(); + await Task.Run(() => { - string progressArrangeParts = "Arranging Parts".Localize(); - string progressArrangePartsFull = string.Format("{0}:", progressArrangeParts); - processingProgressControl.ProcessType = progressArrangePartsFull; - processingProgressControl.Visible = true; - processingProgressControl.PercentComplete = 0; - LockEditControls(); - - List preArrangeTarnsforms = new List(MeshGroupTransforms); - - await Task.Run(() => + foreach (var sceneItem in Scene.Children) { - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - PushMeshGroupDataToAsynchLists(TraceInfoOpperation.DONT_COPY); - PlatingHelper.ArrangeMeshGroups(asyncMeshGroups, asyncMeshGroupTransforms, asyncPlatingDatas, ReportProgressChanged); - }); + PlatingHelper.MoveToOpenPosition(sceneItem, Scene); - if (HasBeenClosed) - { - return; + arrangedScene.Children.Add(sceneItem); } + }); - // offset them to the center of the bed - for (int i = 0; i < asyncMeshGroups.Count; i++) - { - asyncMeshGroupTransforms[i] *= Matrix4X4.CreateTranslation(new Vector3(ActiveSliceSettings.Instance.GetValue(SettingsKey.print_center), 0)); - } - - PartHasBeenChanged(); - - PullMeshGroupDataFromAsynchLists(); - List postArrangeTarnsforms = new List(MeshGroupTransforms); - - UndoBuffer.Add(new ArangeUndoCommand(this, preArrangeTarnsforms, postArrangeTarnsforms)); - - UnlockEditControls(); - } + Scene.ModifyChildren(children => + { + children.Clear(); + children.AddRange(arrangedScene.Children); + }); } } + + /* + private async void AutoArrangePartsInBackground() + { + if (MeshGroups.Count > 0) + { + string progressArrangeParts = LocalizedString.Get("Arranging Parts"); + string progressArrangePartsFull = string.Format("{0}:", progressArrangeParts); + processingProgressControl.ProcessType = progressArrangePartsFull; + processingProgressControl.Visible = true; + processingProgressControl.PercentComplete = 0; + LockEditControls(); + + List preArrangeTarnsforms = new List(MeshGroupTransforms); + + await Task.Run(() => + { + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + PushMeshGroupDataToAsynchLists(TraceInfoOpperation.DONT_COPY); + PlatingHelper.ArrangeMeshGroups(asyncMeshGroups, asyncMeshGroupTransforms, asyncPlatingDatas, ReportProgressChanged); + }); + + if (WidgetHasBeenClosed) + { + return; + } + + // offset them to the center of the bed + for (int i = 0; i < asyncMeshGroups.Count; i++) + { + asyncMeshGroupTransforms[i] *= Matrix4X4.CreateTranslation(new Vector3(ActiveSliceSettings.Instance.BedCenter, 0)); + } + + PartHasBeenChanged(); + + PullMeshGroupDataFromAsynchLists(); + List postArrangeTarnsforms = new List(MeshGroupTransforms); + + undoBuffer.Add(new ArangeUndoCommand(this, preArrangeTarnsforms, postArrangeTarnsforms)); + + UnlockEditControls(); + } + } */ } \ No newline at end of file diff --git a/PartPreviewWindow/View3D/View3DCopyGroup.cs b/PartPreviewWindow/View3D/View3DCopyGroup.cs index 5612f9ee8..3c84825f1 100644 --- a/PartPreviewWindow/View3D/View3DCopyGroup.cs +++ b/PartPreviewWindow/View3D/View3DCopyGroup.cs @@ -27,69 +27,72 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ +using MatterHackers.DataConverters3D; using MatterHackers.Localizations; -using MatterHackers.PolygonMesh; -using System.ComponentModel; -using System.Globalization; -using System.Threading; +using System.Linq; using System.Threading.Tasks; +using System.Diagnostics; +using MatterHackers.VectorMath; +using MatterHackers.MeshVisualizer; namespace MatterHackers.MatterControl.PartPreviewWindow { public partial class View3DWidget { - private void CopyGroup() - { - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - - PushMeshGroupDataToAsynchLists(TraceInfoOpperation.DO_COPY); - - MeshGroup meshGroupToCopy = asyncMeshGroups[SelectedMeshGroupIndex]; - MeshGroup copyMeshGroup = new MeshGroup(); - double meshCount = meshGroupToCopy.Meshes.Count; - for (int i = 0; i < meshCount; i++) - { - Mesh mesh = asyncMeshGroups[SelectedMeshGroupIndex].Meshes[i]; - copyMeshGroup.Meshes.Add(Mesh.Copy(mesh, (double progress0To1, string processingState, out bool continueProcessing) => - { - ReportProgressChanged(progress0To1, processingState, out continueProcessing); - })); - } - - PlatingHelper.FindPositionForGroupAndAddToPlate(copyMeshGroup, SelectedMeshGroupTransform, asyncPlatingDatas, asyncMeshGroups, asyncMeshGroupTransforms); - PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, asyncMeshGroups.Count - 1, null); - - bool continueProcessing2; - ReportProgressChanged(.95, "", out continueProcessing2); - } - private async void MakeCopyOfGroup() { - if (MeshGroups.Count > 0 - && SelectedMeshGroupIndex != -1) + if (Scene.HasSelection) { - string makingCopyLabel = "Making Copy".Localize(); - string makingCopyLabelFull = string.Format("{0}:", makingCopyLabel); - processingProgressControl.ProcessType = makingCopyLabelFull; + processingProgressControl.ProcessType = "Making Copy".Localize() + ":"; processingProgressControl.Visible = true; processingProgressControl.PercentComplete = 0; LockEditControls(); - await Task.Run((System.Action)CopyGroup); + // Copy selected item + IObject3D newItem = await Task.Run(() => + { + var clonedItem = Scene.SelectedItem.Clone(); + PlatingHelper.MoveToOpenPosition(clonedItem, Scene); + + return clonedItem; + }); if (HasBeenClosed) { return; } + InsertNewItem(newItem); + UnlockEditControls(); - PullMeshGroupDataFromAsynchLists(); PartHasBeenChanged(); + // TODO: jlewin - why do we need to reset the scale? + // now set the selection to the new copy - SelectedMeshGroupIndex = MeshGroups.Count - 1; - UndoBuffer.Add(new CopyUndoCommand(this, SelectedMeshGroupIndex)); + Scene.Children.Last().ExtraData.CurrentScale = Scene.SelectedItem.ExtraData.CurrentScale; } } + + public void InsertNewItem(IObject3D newItem) + { + // Reposition first item to bed center + if (Scene.Children.Count == 0) + { + var aabb = newItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + var center = aabb.Center; + newItem.Matrix *= Matrix4X4.CreateTranslation( + (MeshViewerWidget.BedCenter.x + center.x), + (MeshViewerWidget.BedCenter.y + center.y), + -aabb.minXYZ.z); + } + + // Create and perform a new insert operation + var insertOperation = new InsertCommand(this, newItem); + insertOperation.Do(); + + // Store the operation for undo/redo + UndoBuffer.Add(insertOperation); + } } } \ No newline at end of file diff --git a/PartPreviewWindow/View3D/View3DGroup.cs b/PartPreviewWindow/View3D/View3DGroup.cs index 201a27de8..3e71a6b22 100644 --- a/PartPreviewWindow/View3D/View3DGroup.cs +++ b/PartPreviewWindow/View3D/View3DGroup.cs @@ -27,109 +27,44 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ -using MatterHackers.Localizations; -using MatterHackers.MeshVisualizer; -using MatterHackers.PolygonMesh; -using MatterHackers.VectorMath; -using System.ComponentModel; -using System.Globalization; -using System.Threading; +using MatterHackers.DataConverters3D; using System.Threading.Tasks; namespace MatterHackers.MatterControl.PartPreviewWindow { public partial class View3DWidget { - private void GroupSelected() - { - string makingCopyLabel = "Grouping".Localize(); - string makingCopyLabelFull = string.Format("{0}:", makingCopyLabel); - processingProgressControl.ProcessType = makingCopyLabelFull; - - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - - PushMeshGroupDataToAsynchLists(TraceInfoOpperation.DO_COPY); - - for (int i = 0; i < asyncMeshGroups.Count; i++) - { - asyncMeshGroups[i].Transform(asyncMeshGroupTransforms[i]); - - bool continueProcessing; - ReportProgressChanged((i + 1) * .4 / asyncMeshGroups.Count, "", out continueProcessing); - } - - if (SelectedMeshGroupIndex == -1) - { - SelectedMeshGroupIndex = 0; - } - - MeshGroup meshGroupWeAreKeeping = asyncMeshGroups[SelectedMeshGroupIndex]; - for (int meshGroupToMoveIndex = asyncMeshGroups.Count - 1; meshGroupToMoveIndex >= 0; meshGroupToMoveIndex--) - { - MeshGroup meshGroupToMove = asyncMeshGroups[meshGroupToMoveIndex]; - if (meshGroupToMove != meshGroupWeAreKeeping) - { - for (int moveIndex = 0; moveIndex < meshGroupToMove.Meshes.Count; moveIndex++) - { - Mesh mesh = meshGroupToMove.Meshes[moveIndex]; - meshGroupWeAreKeeping.Meshes.Add(mesh); - } - - asyncMeshGroups.RemoveAt(meshGroupToMoveIndex); - asyncMeshGroupTransforms.RemoveAt(meshGroupToMoveIndex); - } - else - { - asyncMeshGroupTransforms[meshGroupToMoveIndex] = Matrix4X4.Identity; - } - } - - asyncPlatingDatas.Clear(); - double ratioPerMeshGroup = 1.0 / asyncMeshGroups.Count; - double currentRatioDone = 0; - for (int i = 0; i < asyncMeshGroups.Count; i++) - { - PlatingMeshGroupData newInfo = new PlatingMeshGroupData(); - asyncPlatingDatas.Add(newInfo); - - MeshGroup meshGroup = asyncMeshGroups[i]; - - // create the selection info - PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, i, (double progress0To1, string processingState, out bool continueProcessing) => - { - ReportProgressChanged(progress0To1, processingState, out continueProcessing); - }); - - currentRatioDone += ratioPerMeshGroup; - } - } - private async void GroupSelectedMeshs() { - if (MeshGroups.Count > 0) + if (Scene.HasChildren) { processingProgressControl.PercentComplete = 0; processingProgressControl.Visible = true; LockEditControls(); viewIsInEditModePreLock = true; - await Task.Run((System.Action)GroupSelected); + var item = Scene.SelectedItem; + + await Task.Run(() => + { + if (Scene.IsSelected(Object3DTypes.SelectionGroup)) + { + // Create and perform the delete operation + var operation = new GroupCommand(this, Scene.SelectedItem); + operation.Do(); + + // Store the operation for undo/redo + UndoBuffer.Add(operation); + } + }); if (HasBeenClosed) { return; } - // remove the original mesh and replace it with these new meshes - PullMeshGroupDataFromAsynchLists(); - - // our selection changed to the mesh we just added which is at the end - SelectedMeshGroupIndex = MeshGroups.Count - 1; - UnlockEditControls(); - PartHasBeenChanged(); - Invalidate(); } } diff --git a/PartPreviewWindow/View3D/View3DUngroup.cs b/PartPreviewWindow/View3D/View3DUngroup.cs index b8a47e81d..da14a5e49 100644 --- a/PartPreviewWindow/View3D/View3DUngroup.cs +++ b/PartPreviewWindow/View3D/View3DUngroup.cs @@ -27,102 +27,42 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ -using MatterHackers.Localizations; -using MatterHackers.MeshVisualizer; -using MatterHackers.PolygonMesh; -using MatterHackers.VectorMath; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.Threading; +using MatterHackers.DataConverters3D; using System.Threading.Tasks; namespace MatterHackers.MatterControl.PartPreviewWindow { public partial class View3DWidget { - private void UngroupSelected() - { - if (SelectedMeshGroupIndex == -1) - { - SelectedMeshGroupIndex = 0; - } - string makingCopyLabel = "Ungrouping".Localize(); - string makingCopyLabelFull = string.Format("{0}:", makingCopyLabel); - processingProgressControl.ProcessType = makingCopyLabelFull; - - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - - PushMeshGroupDataToAsynchLists(TraceInfoOpperation.DO_COPY); - - int indexBeingReplaced = SelectedMeshGroupIndex; - List discreetMeshes = new List(); - asyncMeshGroups[indexBeingReplaced].Transform(asyncMeshGroupTransforms[indexBeingReplaced]); - // if there are multiple meshes than just make them separate groups - if (asyncMeshGroups[indexBeingReplaced].Meshes.Count > 1) - { - foreach (Mesh mesh in asyncMeshGroups[indexBeingReplaced].Meshes) - { - discreetMeshes.Add(mesh); - } - } - else // actually try and cut up the mesh into separate parts - { - discreetMeshes = CreateDiscreteMeshes.SplitConnectedIntoMeshes(asyncMeshGroups[indexBeingReplaced], (double progress0To1, string processingState, out bool continueProcessing) => - { - ReportProgressChanged(progress0To1 * .5, processingState, out continueProcessing); - }); - } - - asyncMeshGroups.RemoveAt(indexBeingReplaced); - asyncPlatingDatas.RemoveAt(indexBeingReplaced); - asyncMeshGroupTransforms.RemoveAt(indexBeingReplaced); - double ratioPerDiscreetMesh = 1.0 / discreetMeshes.Count; - double currentRatioDone = 0; - for (int discreetMeshIndex = 0; discreetMeshIndex < discreetMeshes.Count; discreetMeshIndex++) - { - PlatingMeshGroupData newInfo = new PlatingMeshGroupData(); - asyncPlatingDatas.Add(newInfo); - asyncMeshGroups.Add(new MeshGroup(discreetMeshes[discreetMeshIndex])); - int addedMeshIndex = asyncMeshGroups.Count - 1; - MeshGroup addedMeshGroup = asyncMeshGroups[addedMeshIndex]; - - Matrix4X4 transform = Matrix4X4.Identity; - asyncMeshGroupTransforms.Add(transform); - - //PlatingHelper.PlaceMeshGroupOnBed(asyncMeshGroups, asyncMeshGroupTransforms, addedMeshIndex, false); - - // and create selection info - PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, addedMeshIndex, (double progress0To1, string processingState, out bool continueProcessing) => - { - ReportProgressChanged(.5 + progress0To1 * .5 * currentRatioDone, processingState, out continueProcessing); - }); - currentRatioDone += ratioPerDiscreetMesh; - } - } - private async void UngroupSelectedMeshGroup() { - if (MeshGroups.Count > 0) + if (Scene.HasChildren) { processingProgressControl.PercentComplete = 0; processingProgressControl.Visible = true; LockEditControls(); viewIsInEditModePreLock = true; - await Task.Run((System.Action)UngroupSelected); + await Task.Run(() => + { + if (Scene.IsSelected(Object3DTypes.Group)) + { + // Create and perform the delete operation + var operation = new UngroupCommand(this, Scene.SelectedItem); + operation.Do(); + + // Store the operation for undo/redo + UndoBuffer.Add(operation); + } + }); if (HasBeenClosed) { return; } - // remove the original mesh and replace it with these new meshes - PullMeshGroupDataFromAsynchLists(); - // our selection changed to the mesh we just added which is at the end - SelectedMeshGroupIndex = MeshGroups.Count - 1; + Scene.SelectLastChild(); UnlockEditControls(); diff --git a/PartPreviewWindow/View3D/View3DWidget.cs b/PartPreviewWindow/View3D/View3DWidget.cs index 45f72f58d..af65a6eb0 100644 --- a/PartPreviewWindow/View3D/View3DWidget.cs +++ b/PartPreviewWindow/View3D/View3DWidget.cs @@ -26,8 +26,6 @@ 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. */ -//#define DoBooleanTest - using MatterHackers.Agg; using MatterHackers.Agg.Image; using MatterHackers.Agg.ImageProcessing; @@ -35,6 +33,7 @@ using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.Transform; using MatterHackers.Agg.UI; using MatterHackers.Agg.VertexSource; +using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MatterControl.CustomWidgets; using MatterHackers.MatterControl.DataStorage; @@ -49,6 +48,7 @@ using MatterHackers.RayTracer; using MatterHackers.RayTracer.Traceable; using MatterHackers.RenderOpenGl; using MatterHackers.VectorMath; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -59,14 +59,109 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using System.Xml.Linq; namespace MatterHackers.MatterControl.PartPreviewWindow { + public class BaseObject3DEditor : IObject3DEditor + { + private IObject3D item; + private View3DWidget view3DWidget; + + public string Name { get { return "General"; } } + + public IEnumerable SupportedTypes() + { + return new Type[] { typeof(Object3D) }; + } + + public GuiWidget Create(IObject3D item, View3DWidget view3DWidget) + { + this.view3DWidget = view3DWidget; + this.item = item; + FlowLayoutWidget mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); + + FlowLayoutWidget tabContainer = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + HAnchor = HAnchor.AbsolutePosition, + Visible = true, + Width = view3DWidget.WhiteButtonFactory.FixedWidth + }; + mainContainer.AddChild(tabContainer); + + Button updateButton = view3DWidget.textImageButtonFactory.Generate("Color".Localize()); + updateButton.Margin = new BorderDouble(5); + updateButton.HAnchor = HAnchor.ParentRight; + updateButton.Click += ChangeColor; + tabContainer.AddChild(updateButton); + + return mainContainer; + } + + Random rand = new Random(); + private void ChangeColor(object sender, EventArgs e) + { + item.Color = new RGBA_Bytes(rand.Next(255), rand.Next(255), rand.Next(255)); + view3DWidget.Invalidate(); + } + } + public interface IInteractionVolumeCreator { InteractionVolume CreateInteractionVolume(View3DWidget widget); } + public class DragDropLoadProgress + { + IObject3D trackingObject; + View3DWidget view3DWidget; + private ProgressBar progressBar; + + public DragDropLoadProgress(View3DWidget view3DWidget, IObject3D trackingObject) + { + this.trackingObject = trackingObject; + this.view3DWidget = view3DWidget; + view3DWidget.AfterDraw += View3DWidget_AfterDraw; + progressBar = new ProgressBar(80, 15) + { + FillColor = ActiveTheme.Instance.PrimaryAccentColor, + }; + } + + private void View3DWidget_AfterDraw(object sender, DrawEventArgs e) + { + if (view3DWidget?.meshViewerWidget?.TrackballTumbleWidget != null) + { + AxisAlignedBoundingBox bounds = trackingObject.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + Vector3 renderPosition = bounds.Center; + Vector2 cornerScreenSpace = view3DWidget.meshViewerWidget.TrackballTumbleWidget.GetScreenPosition(renderPosition) - new Vector2(40, 20); + + e.graphics2D.PushTransform(); + Affine currentGraphics2DTransform = e.graphics2D.GetTransform(); + Affine accumulatedTransform = currentGraphics2DTransform * Affine.NewTranslation(cornerScreenSpace.x, cornerScreenSpace.y); + e.graphics2D.SetTransform(accumulatedTransform); + + progressBar.OnDraw(e.graphics2D); + e.graphics2D.PopTransform(); + } + } + + public void UpdateLoadProgress(double progress0To1, string processingState, out bool continueProcessing) + { + continueProcessing = true; + progressBar.RatioComplete = progress0To1; + if (progress0To1 == 1) + { + if (view3DWidget != null) + { + view3DWidget.AfterDraw -= View3DWidget_AfterDraw; + } + + view3DWidget = null; + } + } + } + public class InteractionVolumePlugin : IInteractionVolumeCreator { public virtual InteractionVolume CreateInteractionVolume(View3DWidget widget) @@ -78,7 +173,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public interface ISideBarToolCreator { GuiWidget CreateSideBarTool(View3DWidget widget); - } + } public class SideBarPlugin : ISideBarToolCreator { @@ -90,34 +185,28 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public partial class View3DWidget : PartPreview3DWidget { + private bool DoBooleanTest = false; + public FlowLayoutWidget doEdittingButtonsContainer; public UndoBuffer UndoBuffer { get; private set; } = new UndoBuffer(); public readonly int EditButtonHeight = 44; + + private static string PartsNotPrintableMessage = "Parts are not on the bed or outside the print area.\n\nWould you like to center them on the bed?".Localize(); + private static string PartsNotPrintableTitle = "Parts not in print area".Localize(); + private Action afterSaveCallback = null; - private List asyncMeshGroups = new List(); - private List asyncMeshGroupTransforms = new List(); - private List asyncPlatingDatas = new List(); - private FlowLayoutWidget doEdittingButtonsContainer; private bool editorThatRequestedSave = false; private FlowLayoutWidget enterEditButtonsContainer; - private CheckBox expandMaterialOptions; - private CheckBox expandRotateOptions; - private CheckBox expandViewOptions; private ExportPrintItemWindow exportingWindow = null; private ObservableCollection extruderButtons = new ObservableCollection(); private bool hasDrawn = false; - private FlowLayoutWidget materialOptionContainer; - public List MeshGroupExtraData { get; private set; } - public MeshSelectInfo CurrentSelectInfo { get; private set; } = new MeshSelectInfo(); + private OpenMode openMode; private bool partHasBeenEdited = false; - private List pendingPartsToLoad = new List(); - private PrintItemWrapper printItemWrapper; + private PrintItemWrapper printItemWrapper { get; set; } private ProgressControl processingProgressControl; - private FlowLayoutWidget rotateOptionContainer; private SaveAsWindow saveAsWindow = null; private SplitButton saveButtons; private bool saveSucceded = true; - private EventHandler SelectionChanged; private RGBA_Bytes[] SelectionColors = new RGBA_Bytes[] { new RGBA_Bytes(131, 4, 66), new RGBA_Bytes(227, 31, 61), new RGBA_Bytes(255, 148, 1), new RGBA_Bytes(247, 224, 23), new RGBA_Bytes(143, 212, 1) }; private Stopwatch timeSinceLastSpin = new Stopwatch(); private Stopwatch timeSinceReported = new Stopwatch(); @@ -126,11 +215,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private bool viewIsInEditModePreLock = false; - private FlowLayoutWidget viewOptionContainer; - private bool wasInSelectMode = false; public event EventHandler SelectedTransformChanged; + public View3DWidgetSidebar Sidebar; public static ImageBuffer ArrowRight { @@ -161,6 +249,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } } } + protected FlowLayoutWidget editPlateButtonsContainer; public View3DWidget(PrintItemWrapper printItemWrapper, Vector3 viewerVolume, Vector2 bedCenter, BedShape bedShape, WindowMode windowType, AutoRotate autoRotate, OpenMode openMode = OpenMode.Viewing) { @@ -168,8 +257,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow this.windowType = windowType; allowAutoRotate = (autoRotate == AutoRotate.Enabled); autoRotating = allowAutoRotate; - MeshGroupExtraData = new List(); - MeshGroupExtraData.Add(new PlatingMeshGroupData()); this.printItemWrapper = printItemWrapper; this.Name = "View3DWidget"; @@ -185,7 +272,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow GuiWidget viewArea = new GuiWidget(); viewArea.AnchorAll(); { - meshViewerWidget = new MeshViewerWidget(viewerVolume, bedCenter, bedShape, "Press 'Add' to select an item.".Localize()); + meshViewerWidget = new MeshViewerWidget(viewerVolume, bedCenter, bedShape); PutOemImageOnBed(); @@ -201,9 +288,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow buttonBottomPanel.Padding = new BorderDouble(3, 3); buttonBottomPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - buttonRightPanel = CreateRightButtonPanel(viewerVolume.y); - buttonRightPanel.Name = "buttonRightPanel"; - buttonRightPanel.Visible = false; + Sidebar = new View3DWidgetSidebar(this, viewerVolume.y, UndoBuffer); + Sidebar.Name = "buttonRightPanel"; + Sidebar.Visible = false; + Sidebar.InitializeComponents(); + + Scene.SelectionChanged += Scene_SelectionChanged; CreateOptionsContent(); @@ -231,8 +321,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { UiThread.RunOnIdle(() => { - DoAddFileAfterCreatingEditData = true; - EnterEditAndCreateSelectionData(); + SwitchStateToEditing(); }); }; if (printItemWrapper != null @@ -248,7 +337,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow enterEdittingButton.Margin = new BorderDouble(right: 4); enterEdittingButton.Click += (sender, e) => { - EnterEditAndCreateSelectionData(); + SwitchStateToEditing(); }; if (printItemWrapper != null @@ -305,7 +394,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow ungroupButton.Click += (sender, e) => { UngroupSelectedMeshGroup(); - UndoBuffer.ClearHistory(); }; Button groupButton = textImageButtonFactory.Generate("Group".Localize()); @@ -314,7 +402,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow groupButton.Click += (sender, e) => { GroupSelectedMeshs(); - UndoBuffer.ClearHistory(); }; Button alignButton = textImageButtonFactory.Generate("Align".Localize()); @@ -322,7 +409,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow alignButton.Click += (sender, e) => { AlignToSelectedMeshGroup(); - UndoBuffer.ClearHistory(); }; Button arrangeButton = textImageButtonFactory.Generate("Arrange".Localize()); @@ -368,13 +454,17 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { if (saveButtons.Visible) { - StyledMessageBox.ShowMessageBox(ExitEditingAndSaveIfRequired, "Would you like to save your changes before exiting the editor?".Localize(), "Save Changes".Localize(), StyledMessageBox.MessageType.YES_NO, "Save Changed".Localize(), "Discard Changes".Localize()); + StyledMessageBox.ShowMessageBox( + ExitEditingAndSaveIfRequested, + "Would you like to save your changes before exiting the editor?".Localize(), + "Save Changes".Localize(), + StyledMessageBox.MessageType.YES_NO); } else { if (partHasBeenEdited) { - ExitEditingAndSaveIfRequired(false); + ExitEditingAndSaveIfRequested(false); } else { @@ -401,14 +491,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow }; buttonRightPanelHolder.Name = "buttonRightPanelHolder"; centerPartPreviewAndControls.AddChild(buttonRightPanelHolder); - buttonRightPanelHolder.AddChild(buttonRightPanel); - buttonRightPanel.VisibleChanged += (sender, e) => + buttonRightPanelHolder.AddChild(Sidebar); + Sidebar.VisibleChanged += (sender, e) => { - buttonRightPanelHolder.Visible = buttonRightPanel.Visible; + buttonRightPanelHolder.Visible = Sidebar.Visible; }; viewControls3D = new ViewControls3D(meshViewerWidget); - viewControls3D.ResetView += (sender, e) => { meshViewerWidget.ResetView(); @@ -447,6 +536,24 @@ namespace MatterHackers.MatterControl.PartPreviewWindow meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation; AddChild(viewControls3D); + + /* TODO: Why doesn't this pattern work but using new SelectedObjectPanel object does? + selectedObjectPanel = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + Width = 215, + Margin = new BorderDouble(0, 0, buttonRightPanel.Width + 5, 5), + BackgroundColor = RGBA_Bytes.Red, + HAnchor = HAnchor.ParentRight, + VAnchor = VAnchor.ParentTop + }; */ + + selectedObjectPanel = new SelectedObjectPanel() + { + Margin = new BorderDouble(0, 0, Sidebar.Width + 5, 5), + }; + + AddChild(selectedObjectPanel); + UiThread.RunOnIdle(AutoSpin); if (printItemWrapper == null && windowType == WindowMode.Embeded) @@ -492,20 +599,50 @@ namespace MatterHackers.MatterControl.PartPreviewWindow meshViewerWidget.ResetView(); -#if DoBooleanTest - DrawBefore += CreateBooleanTestGeometry; - DrawAfter += RemoveBooleanTestGeometry; -#endif - meshViewerWidget.TrackballTumbleWidget.DrawGlContent += trackballTumbleWidget_DrawGlContent; - + if (DoBooleanTest) + { + BeforeDraw += CreateBooleanTestGeometry; + AfterDraw += RemoveBooleanTestGeometry; + } + meshViewerWidget.TrackballTumbleWidget.DrawGlContent += TrackballTumbleWidget_DrawGlContent; } - private void trackballTumbleWidget_DrawGlContent(object sender, EventArgs e) + public void SelectAll() { - if(allObjects != null) + Scene.ClearSelection(); + foreach(var child in Scene.Children) { - //DebugBvh.Render(allObjects, Matrix4X4.Identity); - } + Scene.AddToSelection(child); + } + } + + private IObject3D dragDropSource; + public IObject3D DragDropSource + { + get + { + return dragDropSource; + } + + set + { + if (InEditMode) + { + dragDropSource = value; + + // Suppress ui volumes when dragDropSource is not null + meshViewerWidget.SuppressUiVolumes = (dragDropSource != null); + } + } + } + + private void TrackballTumbleWidget_DrawGlContent(object sender, EventArgs e) + { + return; + if (Scene?.TraceData() != null) + { + Scene.TraceData().RenderBvhRecursive(Scene.Matrix, 0, 3); + } } public override void OnKeyDown(KeyEventArgs keyEvent) @@ -530,6 +667,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow switch (keyEvent.KeyCode) { + case Keys.A: + if (keyEvent.Control) + { + SelectAll(); + keyEvent.Handled = true; + keyEvent.SuppressKeyPress = true; + } + break; + case Keys.Z: if (keyEvent.Control) { @@ -558,7 +704,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { CurrentSelectInfo.DownOnPart = false; - SelectedMeshGroupTransform = transformOnMouseDown; + Scene.SelectedItem.Matrix = transformOnMouseDown; Invalidate(); } @@ -568,105 +714,71 @@ namespace MatterHackers.MatterControl.PartPreviewWindow base.OnKeyDown(keyEvent); } + public bool IsEditing { get; private set; } + public bool DragingPart { get { return CurrentSelectInfo.DownOnPart; } } - private void AddGridSnapSettings(GuiWidget widgetToAddTo) + public void AddUndoOperation(IUndoRedoCommand operation) { - FlowLayoutWidget container = new FlowLayoutWidget() - { - Margin = new BorderDouble(5, 0), - }; - - TextWidget snapGridLabel = new TextWidget("Snap Grid".Localize()) - { - TextColor = ActiveTheme.Instance.PrimaryTextColor, - VAnchor = VAnchor.ParentCenter, - Margin = new BorderDouble(3, 0, 0, 0), - }; - - container.AddChild(snapGridLabel); - - DropDownList selectableOptions = new DropDownList("Custom", Direction.Up) - { - VAnchor = VAnchor.ParentCenter | VAnchor.FitToChildren, - }; - - Dictionary snapSettings = new Dictionary() - { - { 0, "Off" }, - { .1, "0.1" }, - { .25, "0.25" }, - { .5, "0.5" }, - { 1, "1" }, - { 2, "2" }, - { 5, "5" }, - }; - - foreach (KeyValuePair snapSetting in snapSettings) - { - double valueLocal = snapSetting.Key; - - MenuItem newItem = selectableOptions.AddItem(snapSetting.Value); - if (meshViewerWidget.SnapGridDistance == valueLocal) - { - selectableOptions.SelectedLabel = snapSetting.Value; - } - - newItem.Selected += (sender, e) => - { - meshViewerWidget.SnapGridDistance = snapSetting.Key; - }; - } - - container.AddChild(selectableOptions); - - widgetToAddTo.AddChild(container); + UndoBuffer.Add(operation); } -#if DoBooleanTest - MeshGroup booleanGroup; - Matrix4X4 groupTransform; +#region DoBooleanTest + Object3D booleanGroup; Vector3 offset = new Vector3(); Vector3 direction = new Vector3(.11, .12, .13); Vector3 rotCurrent = new Vector3(); Vector3 rotChange = new Vector3(.011, .012, .013); Vector3 scaleChange = new Vector3(.0011, .0012, .0013); Vector3 scaleCurrent = new Vector3(1, 1, 1); - private void CreateBooleanTestGeometry(GuiWidget drawingWidget, DrawEventArgs e) + + private void CreateBooleanTestGeometry(object sender, DrawEventArgs e) { try { - booleanGroup = new MeshGroup(); + booleanGroup = new Object3D { ItemType = Object3DTypes.Group }; - booleanGroup.Meshes.Add(ApplyBoolean(PolygonMesh.Csg.CsgOperations.Union, AxisAlignedBoundingBox.Union, new Vector3(100, 0, 20), "U")); - booleanGroup.Meshes.Add(ApplyBoolean(PolygonMesh.Csg.CsgOperations.Subtract, null, new Vector3(100, 100, 20), "S")); - booleanGroup.Meshes.Add(ApplyBoolean(PolygonMesh.Csg.CsgOperations.Intersect, AxisAlignedBoundingBox.Intersection , new Vector3(100, 200, 20), "I")); + booleanGroup.Children.Add(new Object3D() + { + Mesh = ApplyBoolean(PolygonMesh.Csg.CsgOperations.Union, AxisAlignedBoundingBox.Union, new Vector3(100, 0, 20), "U") + }); + + booleanGroup.Children.Add(new Object3D() + { + Mesh = ApplyBoolean(PolygonMesh.Csg.CsgOperations.Subtract, null, new Vector3(100, 100, 20), "S") + }); + + booleanGroup.Children.Add(new Object3D() + { + Mesh = ApplyBoolean(PolygonMesh.Csg.CsgOperations.Intersect, AxisAlignedBoundingBox.Intersection, new Vector3(100, 200, 20), "I") + }); offset += direction; rotCurrent += rotChange; scaleCurrent += scaleChange; - meshViewerWidget.MeshGroups.Add(booleanGroup); - groupTransform = Matrix4X4.Identity; - meshViewerWidget.MeshGroupTransforms.Add(groupTransform); + Scene.ModifyChildren(children => + { + children.Add(booleanGroup); + }); } catch(Exception e2) { string text = e2.Message; - int a = 0; + int a = 0; } } private Mesh ApplyBoolean(Func meshOpperation, Func aabbOpperation, Vector3 centering, string opp) { Mesh boxA = PlatonicSolids.CreateCube(40, 40, 40); - boxA = PlatonicSolids.CreateIcosahedron(35); + //boxA = PlatonicSolids.CreateIcosahedron(35); boxA.Translate(centering); Mesh boxB = PlatonicSolids.CreateCube(40, 40, 40); - boxB = PlatonicSolids.CreateIcosahedron(35); + //boxB = PlatonicSolids.CreateIcosahedron(35); for (int i = 0; i < 3; i++) { @@ -728,16 +840,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow return meshToAdd; } - private void RemoveBooleanTestGeometry(GuiWidget drawingWidget, DrawEventArgs e) + private void RemoveBooleanTestGeometry(object sender, DrawEventArgs e) { - if (meshViewerWidget.MeshGroups.Contains(booleanGroup)) + if (meshViewerWidget.Scene.Children.Contains(booleanGroup)) { - meshViewerWidget.MeshGroups.Remove(booleanGroup); - meshViewerWidget.MeshGroupTransforms.Remove(groupTransform); + meshViewerWidget.Scene.Children.Remove(booleanGroup); UiThread.RunOnIdle(() => Invalidate(), 1.0 / 30.0); } } -#endif + #endregion DoBooleanTest public enum AutoRotate { Enabled, Disabled }; @@ -745,146 +856,216 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public enum WindowMode { Embeded, StandAlone }; - private enum TraceInfoOpperation { DONT_COPY, DO_COPY }; - public bool DisplayAllValueData { get; set; } - public bool HaveSelection - { - get { return MeshGroups.Count > 0 && SelectedMeshGroupIndex > -1; } - } - - public List MeshGroups - { - get { return meshViewerWidget.MeshGroups; } - } - - public List MeshGroupTransforms - { - get { return meshViewerWidget.MeshGroupTransforms; } - } - - public MeshGroup SelectedMeshGroup - { - get { return meshViewerWidget.SelectedMeshGroup; } - } - - public int SelectedMeshGroupIndex - { - get - { - return meshViewerWidget.SelectedMeshGroupIndex; - } - set - { - if (value != SelectedMeshGroupIndex) - { - meshViewerWidget.SelectedMeshGroupIndex = value; - if (SelectionChanged != null) - { - SelectionChanged(this, null); - } - Invalidate(); - } - } - } - - public Matrix4X4 SelectedMeshGroupTransform - { - get { return meshViewerWidget.SelectedMeshGroupTransform; } - set { meshViewerWidget.SelectedMeshGroupTransform = value; } - } - public WindowMode windowType { get; set; } - private bool DoAddFileAfterCreatingEditData { get; set; } public override void OnClosed(ClosedEventArgs e) { - if (unregisterEvents != null) - { - unregisterEvents(this, null); - } - + unregisterEvents?.Invoke(this, null); base.OnClosed(e); } - public override void OnDragDrop(FileDropEventArgs fileDropEventArgs) + // TODO: Just realized we don't implement DragLeave, meaning that injected items can't be removed. Must implement + public override void OnDragDrop(FileDropEventArgs fileDropArgs) { - if (AllowDragDrop()) + if (AllowDragDrop() && fileDropArgs.DroppedFiles.Count == 1) { - pendingPartsToLoad.Clear(); - foreach (string droppedFileName in fileDropEventArgs.DroppedFiles) - { - string extension = Path.GetExtension(droppedFileName).ToLower(); - if (extension != "" && ApplicationSettings.OpenDesignFileParams.Contains(extension)) - { - pendingPartsToLoad.Add(droppedFileName); - } - } - - if (pendingPartsToLoad.Count > 0) + // Item is already in the scene + DragDropSource = null; + } + else if (AllowDragDrop()) + { + // Items need to be added to the scene + var partsToAdd = (from droppedFileName in fileDropArgs.DroppedFiles + let extension = Path.GetExtension(droppedFileName).ToLower() + where !string.IsNullOrEmpty(extension) && ApplicationSettings.OpenDesignFileParams.Contains(extension) + select droppedFileName).ToArray(); + + if (partsToAdd.Length > 0) { bool enterEditModeBeforeAddingParts = enterEditButtonsContainer.Visible == true; if (enterEditModeBeforeAddingParts) { - EnterEditAndCreateSelectionData(); - } - else - { - LoadAndAddPartsToPlate(pendingPartsToLoad.ToArray()); - pendingPartsToLoad.Clear(); + SwitchStateToEditing(); } + + loadAndAddPartsToPlate(partsToAdd); } } - base.OnDragDrop(fileDropEventArgs); + base.OnDragDrop(fileDropArgs); } - public override void OnDragEnter(FileDropEventArgs fileDropEventArgs) + public override void OnDragEnter(FileDropEventArgs fileDropArgs) { if (AllowDragDrop()) { - foreach (string file in fileDropEventArgs.DroppedFiles) + foreach (string file in fileDropArgs.DroppedFiles) { string extension = Path.GetExtension(file).ToLower(); if (extension != "" && ApplicationSettings.OpenDesignFileParams.Contains(extension)) { - fileDropEventArgs.AcceptDrop = true; + fileDropArgs.AcceptDrop = true; } } + + if(fileDropArgs.AcceptDrop) + { + DragDropSource = new Object3D + { + ItemType = Object3DTypes.Model, + Mesh = PlatonicSolids.CreateCube(10, 10, 10) + }; + } } - base.OnDragEnter(fileDropEventArgs); + base.OnDragEnter(fileDropArgs); } - public override void OnDragOver(FileDropEventArgs fileDropEventArgs) + public override async void OnDragOver(FileDropEventArgs fileDropArgs) { - if (AllowDragDrop()) + if (AllowDragDrop() && fileDropArgs.DroppedFiles.Count == 1) { - foreach (string file in fileDropEventArgs.DroppedFiles) + var screenSpaceMousePosition = this.TransformToScreenSpace(new Vector2(fileDropArgs.X, fileDropArgs.Y)); + + // If the DragDropSource was added to the scene on this DragOver call, we start a task to replace + // the "loading" mesh with the actual file contents + if (AltDragOver(screenSpaceMousePosition)) { - string extension = Path.GetExtension(file).ToLower(); - if (extension != "" && ApplicationSettings.OpenDesignFileParams.Contains(extension)) - { - fileDropEventArgs.AcceptDrop = true; - } + DragDropSource.MeshPath = fileDropArgs.DroppedFiles.First(); + + // Run the rest of the OnDragOver pipeline since we're starting a new thread and won't finish for an unknown time + base.OnDragOver(fileDropArgs); + + LoadDragSource(); + + // Don't fall through to the base.OnDragOver because we preemptively invoked it above + return; } } - base.OnDragOver(fileDropEventArgs); + + // AcceptDrop anytime a DropSource has been queued + fileDropArgs.AcceptDrop = DragDropSource != null; + + base.OnDragOver(fileDropArgs); + } + + private GuiWidget topMostParent; + + private PlaneShape bedPlane = new PlaneShape(Vector3.UnitZ, 0, null); + + /// + /// Provides a View3DWidget specific drag implementation + /// + /// The screen space mouse position. + /// A value indicating in the DragDropSource was added to the scene + public bool AltDragOver(Vector2 screenSpaceMousePosition) + { + if (this.HasBeenClosed) + { + return false; + } + + bool itemAddedToScene = false; + + var meshViewerPosition = this.meshViewerWidget.TransformToScreenSpace(meshViewerWidget.LocalBounds); + + if (meshViewerPosition.Contains(screenSpaceMousePosition) && DragDropSource != null) + { + var localPosition = this.TransformFromParentSpace(topMostParent, screenSpaceMousePosition); + + // Inject the DragDropSource if it's missing from the scene, using the default "loading" mesh + if (!Scene.Children.Contains(DragDropSource)) + { + // Set the hitplane to the bed plane + CurrentSelectInfo.HitPlane = bedPlane; + + // Find intersection position of the mouse with the bed plane + var intersectInfo = GetIntersectPosition(screenSpaceMousePosition); + if (intersectInfo == null) + { + return false; + } + + // Set the initial transform on the inject part to the current transform mouse position + var sourceItemBounds = DragDropSource.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + var center = sourceItemBounds.Center; + + DragDropSource.Matrix *= Matrix4X4.CreateTranslation(-center.x, -center.y, -sourceItemBounds.minXYZ.z); + DragDropSource.Matrix *= Matrix4X4.CreateTranslation(new Vector3(intersectInfo.hitPosition)); + + CurrentSelectInfo.PlaneDownHitPos = intersectInfo.hitPosition; + CurrentSelectInfo.LastMoveDelta = Vector3.Zero; + + // Add item to scene and select it + Scene.ModifyChildren(children => + { + children.Add(DragDropSource); + }); + Scene.Select(DragDropSource); + + itemAddedToScene = true; + } + + if (Scene.HasSelection) + { + // Pass the mouse position, transformed to local cords, through to the view3D widget to move the target item + localPosition = meshViewerWidget.TransformFromScreenSpace(screenSpaceMousePosition); + DragSelectedObject(localPosition); + } + + return itemAddedToScene; + } + + return false; } public override void OnLoad(EventArgs args) { - ClearBedAndLoadPrintItemWrapper(printItemWrapper); + topMostParent = this.TopmostParent(); base.OnLoad(args); } + /// + /// Loads the referenced DragDropSource object. + /// + /// The drag source at the original time of invocation. + /// + public async Task LoadDragSource() + { + // The drag source at the original time of invocation. + IObject3D dragSource = DragDropSource; + if (dragSource == null) + { + return; + } + + IObject3D loadedItem = await Task.Run(() => + { + return Object3D.Load(dragSource.MeshPath, progress: new DragDropLoadProgress(this, dragSource).UpdateLoadProgress); + }); + + if (loadedItem != null) + { + // TODO: Changing an item in the scene has a risk of collection modified during enumeration errors. This approach works as + // a proof of concept but needs to take the more difficult route of managing state and swapping the dragging instance with + // the new loaded item data + Vector3 meshGroupCenter = loadedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity).Center; + dragSource.Mesh = loadedItem.Mesh; + dragSource.Children.AddRange(loadedItem.Children); + dragSource.Matrix *= Matrix4X4.CreateTranslation(-meshGroupCenter.x, -meshGroupCenter.y, -dragSource.GetAxisAlignedBoundingBox(Matrix4X4.Identity).minXYZ.z); + } + } + public override void OnDraw(Graphics2D graphics2D) { - if (HaveSelection) + if (Scene.HasSelection) { + var selectedItem = Scene.SelectedItem; + foreach (InteractionVolume volume in meshViewerWidget.interactionVolumes) { - volume.SetPosition(); + volume.SetPosition(selectedItem); } } @@ -920,31 +1101,70 @@ namespace MatterHackers.MatterControl.PartPreviewWindow viewControls3D.ActiveButton = ViewControls3DButtons.Translate; } + if(mouseEvent.Button == MouseButtons.Right || + mouseEvent.Button == MouseButtons.Middle) + { + meshViewerWidget.SuppressUiVolumes = true; + } + autoRotating = false; base.OnMouseDown(mouseEvent); + if (meshViewerWidget.TrackballTumbleWidget.UnderMouseState == Agg.UI.UnderMouseState.FirstUnderMouse) { - if (meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None - && mouseEvent.Button == MouseButtons.Left - && ModifierKeys != Keys.Shift + if (mouseEvent.Button == MouseButtons.Left + && + ModifierKeys == Keys.Shift || + ( + meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None && ModifierKeys != Keys.Control - && ModifierKeys != Keys.Alt) + && ModifierKeys != Keys.Alt)) { if (!meshViewerWidget.MouseDownOnInteractionVolume) { - int meshGroupHitIndex; + meshViewerWidget.SuppressUiVolumes = true; + IntersectInfo info = new IntersectInfo(); - if (FindMeshGroupHitPosition(mouseEvent.Position, out meshGroupHitIndex, ref info)) + + IObject3D hitObject = FindHitObject3D(mouseEvent.Position, ref info); + if (hitObject != null) { CurrentSelectInfo.HitPlane = new PlaneShape(Vector3.UnitZ, CurrentSelectInfo.PlaneDownHitPos.z, null); - SelectedMeshGroupIndex = meshGroupHitIndex; - transformOnMouseDown = SelectedMeshGroupTransform; + if (hitObject != Scene.SelectedItem) + { + if (Scene.SelectedItem == null) + { + // No selection exists + Scene.Select(hitObject); + } + else if (ModifierKeys == Keys.Shift && !Scene.SelectedItem.Children.Contains(hitObject)) + { + Scene.AddToSelection(hitObject); + } + else if (Scene.SelectedItem == hitObject || Scene.SelectedItem.Children.Contains(hitObject)) + { + // Selection should not be cleared and drag should occur + } + else if (ModifierKeys != Keys.Shift) + { + Scene.ModifyChildren(children => + { + ClearSelectionApplyChanges(children); + }); + + Scene.Select(hitObject); + } + + PartHasBeenChanged(); + } + + transformOnMouseDown = Scene.SelectedItem.Matrix; Invalidate(); CurrentSelectInfo.DownOnPart = true; - AxisAlignedBoundingBox selectedBounds = meshViewerWidget.GetBoundsForSelection(); + AxisAlignedBoundingBox selectedBounds = meshViewerWidget.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); if (info.hitPosition.x < selectedBounds.Center.x) { @@ -971,7 +1191,19 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } else { - SelectedMeshGroupIndex = -1; + if(!Scene.HasSelection) + { + return; + } + + if(Scene.SelectedItem.ItemType == Object3DTypes.SelectionGroup) + { + Scene.ModifyChildren(ClearSelectionApplyChanges); + } + else + { + Scene.ClearSelection(); + } } SelectedTransformChanged?.Invoke(this, null); @@ -980,71 +1212,91 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } } - public Vector3 LastHitPosition { get; private set; } + public void ClearSelectionApplyChanges(List target) + { + Scene.SelectedItem.CollapseInto(target); + Scene.ClearSelection(); + } + + public IntersectInfo GetIntersectPosition(Vector2 screenSpacePosition) + { + //Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, new Vector2(mouseEvent.X, mouseEvent.Y)); + + // Translate to local + Vector2 localPosition = this.TransformFromScreenSpace(screenSpacePosition); + + Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayForLocalBounds(localPosition); + + return CurrentSelectInfo.HitPlane.GetClosestIntersection(ray); + } + + public void DragSelectedObject(Vector2 localMousePostion) + { + Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, localMousePostion); + Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayForLocalBounds(meshViewerWidgetScreenPosition); + + IntersectInfo info = CurrentSelectInfo.HitPlane.GetClosestIntersection(ray); + if (info != null) + { + // move the mesh back to the start position + { + Matrix4X4 totalTransform = Matrix4X4.CreateTranslation(new Vector3(-CurrentSelectInfo.LastMoveDelta)); + Scene.SelectedItem.Matrix *= totalTransform; + } + + Vector3 delta = info.hitPosition - CurrentSelectInfo.PlaneDownHitPos; + + double snapGridDistance = meshViewerWidget.SnapGridDistance; + if (snapGridDistance > 0) + { + // snap this position to the grid + AxisAlignedBoundingBox selectedBounds = meshViewerWidget.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + + double xSnapOffset = selectedBounds.minXYZ.x; + // snap the x position + if (CurrentSelectInfo.HitQuadrant == HitQuadrant.RB + || CurrentSelectInfo.HitQuadrant == HitQuadrant.RT) + { + // switch to the other side + xSnapOffset = selectedBounds.maxXYZ.x; + } + double xToSnap = xSnapOffset + delta.x; + + double snappedX = ((int)((xToSnap / snapGridDistance) + .5)) * snapGridDistance; + delta.x = snappedX - xSnapOffset; + + double ySnapOffset = selectedBounds.minXYZ.y; + // snap the y position + if (CurrentSelectInfo.HitQuadrant == HitQuadrant.LT + || CurrentSelectInfo.HitQuadrant == HitQuadrant.RT) + { + // switch to the other side + ySnapOffset = selectedBounds.maxXYZ.y; + } + double yToSnap = ySnapOffset + delta.y; + + double snappedY = ((int)((yToSnap / snapGridDistance) + .5)) * snapGridDistance; + delta.y = snappedY - ySnapOffset; + } + + // move the mesh back to the new position + { + Matrix4X4 totalTransform = Matrix4X4.CreateTranslation(new Vector3(delta)); + + Scene.SelectedItem.Matrix *= totalTransform; + + CurrentSelectInfo.LastMoveDelta = delta; + } + + Invalidate(); + } + } public override void OnMouseMove(MouseEventArgs mouseEvent) { - if (meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None && CurrentSelectInfo.DownOnPart) + if (CurrentSelectInfo.DownOnPart && meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None) { - Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, new Vector2(mouseEvent.X, mouseEvent.Y)); - Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayFromScreen(meshViewerWidgetScreenPosition); - IntersectInfo info = CurrentSelectInfo.HitPlane.GetClosestIntersection(ray); - if (info != null) - { - // move the mesh back to the start position - { - Matrix4X4 totalTransform = Matrix4X4.CreateTranslation(new Vector3(-CurrentSelectInfo.LastMoveDelta)); - SelectedMeshGroupTransform *= totalTransform; - } - - Vector3 delta = info.hitPosition - CurrentSelectInfo.PlaneDownHitPos; - - double snapGridDistance = meshViewerWidget.SnapGridDistance; - if (snapGridDistance > 0) - { - // snap this position to the grid - AxisAlignedBoundingBox selectedBounds = meshViewerWidget.GetBoundsForSelection(); - - double xSnapOffset = selectedBounds.minXYZ.x; - // snap the x position - if (CurrentSelectInfo.HitQuadrant == HitQuadrant.RB - || CurrentSelectInfo.HitQuadrant == HitQuadrant.RT) - { - // switch to the other side - xSnapOffset = selectedBounds.maxXYZ.x; - } - double xToSnap = xSnapOffset + delta.x; - - double snappedX = (Math.Round((xToSnap / snapGridDistance))) * snapGridDistance; - delta.x = snappedX - xSnapOffset; - - double ySnapOffset = selectedBounds.minXYZ.y; - // snap the y position - if (CurrentSelectInfo.HitQuadrant == HitQuadrant.LT - || CurrentSelectInfo.HitQuadrant == HitQuadrant.RT) - { - // switch to the other side - ySnapOffset = selectedBounds.maxXYZ.y; - } - double yToSnap = ySnapOffset + delta.y; - - double snappedY = (Math.Round((yToSnap / snapGridDistance))) * snapGridDistance; - delta.y = snappedY - ySnapOffset; - } - - // move the mesh back to the new position - { - Matrix4X4 totalTransform = Matrix4X4.CreateTranslation(new Vector3(delta)); - - SelectedMeshGroupTransform *= totalTransform; - - CurrentSelectInfo.LastMoveDelta = delta; - } - - LastHitPosition = info.hitPosition; - - Invalidate(); - } + DragSelectedObject(new Vector2(mouseEvent.X, mouseEvent.Y)); } base.OnMouseMove(mouseEvent); @@ -1052,9 +1304,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public void AddUndoForSelectedMeshGroupTransform(Matrix4X4 undoTransform) { - if (undoTransform != SelectedMeshGroupTransform) + if (Scene.HasSelection && undoTransform != Scene.SelectedItem?.Matrix) { - UndoBuffer.Add(new TransformUndoCommand(this, SelectedMeshGroupIndex, undoTransform, SelectedMeshGroupTransform)); + UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix)); } } @@ -1064,13 +1316,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow && CurrentSelectInfo.DownOnPart && CurrentSelectInfo.LastMoveDelta != Vector3.Zero) { - if (SelectedMeshGroupTransform != transformOnMouseDown) + if (Scene.SelectedItem.Matrix != transformOnMouseDown) { AddUndoForSelectedMeshGroupTransform(transformOnMouseDown); PartHasBeenChanged(); } } + meshViewerWidget.SuppressUiVolumes = false; + CurrentSelectInfo.DownOnPart = false; if (activeButtonBeforeMouseOverride != null) @@ -1096,7 +1350,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow MeshViewerWidget.SetMaterialColor(1, ActiveTheme.Instance.PrimaryAccentColor); } - private void AddMaterialControls(FlowLayoutWidget buttonPanel) + internal void AddMaterialControls(FlowLayoutWidget buttonPanel) { extruderButtons.Clear(); for (int extruderIndex = 0; extruderIndex < ActiveSliceSettings.Instance.GetValue(SettingsKey.extruder_count); extruderIndex++) @@ -1115,33 +1369,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow int extruderIndexLocal = extruderIndex; extruderSelection.Click += (sender, e) => { - if (SelectedMeshGroupIndex != -1) + if (Scene.HasSelection) { - foreach (Mesh mesh in SelectedMeshGroup.Meshes) + // TODO: In the new model, we probably need to iterate this object and all its children, setting + // some state along the way or modify the tree processing to pass the parent value down the chain + MeshMaterialData material = MeshMaterialData.Get(Scene.SelectedItem.Mesh); + if (material.MaterialIndex != extruderIndexLocal + 1) { - MeshMaterialData material = MeshMaterialData.Get(mesh); - if (material.MaterialIndex != extruderIndexLocal + 1) - { - material.MaterialIndex = extruderIndexLocal + 1; - PartHasBeenChanged(); - } - } - } - }; - - this.SelectionChanged += (sender, e) => - { - if (SelectedMeshGroup != null) - { - Mesh mesh = SelectedMeshGroup.Meshes[0]; - MeshMaterialData material = MeshMaterialData.Get(mesh); - - for (int i = 0; i < extruderButtons.Count; i++) - { - if (material.MaterialIndex - 1 == i) - { - ((RadioButton)extruderButtons[i]).Checked = true; - } + material.MaterialIndex = extruderIndexLocal + 1; + PartHasBeenChanged(); } } }; @@ -1183,14 +1419,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow rotateControls.Add(rotateXButton); rotateXButton.Click += (s, e) => { - if (SelectedMeshGroupIndex != -1) + if (Scene.HasSelection) { double radians = MathHelper.DegreesToRadians(degreesControl.ActuallNumberEdit.Value); Matrix4X4 rotation = Matrix4X4.CreateRotationX(radians); - Matrix4X4 undoTransform = SelectedMeshGroupTransform; - SelectedMeshGroupTransform = PlatingHelper.ApplyAtCenter(SelectedMeshGroup, SelectedMeshGroupTransform, rotation); - PlatingHelper.PlaceMeshGroupOnBed(MeshGroups, MeshGroupTransforms, SelectedMeshGroupIndex); - UndoBuffer.Add(new TransformUndoCommand(this, SelectedMeshGroupIndex, undoTransform, SelectedMeshGroupTransform)); + Matrix4X4 undoTransform = Scene.SelectedItem.Matrix; + Scene.SelectedItem.Matrix = PlatingHelper.ApplyAtCenter(Scene.SelectedItem, rotation); + UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix)); PartHasBeenChanged(); Invalidate(); } @@ -1202,14 +1437,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow rotateControls.Add(rotateYButton); rotateYButton.Click += (s, e) => { - if (SelectedMeshGroupIndex != -1) + if (Scene.HasSelection) { double radians = MathHelper.DegreesToRadians(degreesControl.ActuallNumberEdit.Value); Matrix4X4 rotation = Matrix4X4.CreateRotationY(radians); - Matrix4X4 undoTransform = SelectedMeshGroupTransform; - SelectedMeshGroupTransform = PlatingHelper.ApplyAtCenter(SelectedMeshGroup, SelectedMeshGroupTransform, rotation); - PlatingHelper.PlaceMeshGroupOnBed(MeshGroups, MeshGroupTransforms, SelectedMeshGroupIndex); - UndoBuffer.Add(new TransformUndoCommand(this, SelectedMeshGroupIndex, undoTransform, SelectedMeshGroupTransform)); + Matrix4X4 undoTransform = Scene.SelectedItem.Matrix; + Scene.SelectedItem.Matrix = PlatingHelper.ApplyAtCenter(Scene.SelectedItem, rotation); + UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix)); PartHasBeenChanged(); Invalidate(); } @@ -1221,14 +1455,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow rotateControls.Add(rotateZButton); rotateZButton.Click += (s, e) => { - if (SelectedMeshGroupIndex != -1) + if (Scene.HasSelection) { double radians = MathHelper.DegreesToRadians(degreesControl.ActuallNumberEdit.Value); Matrix4X4 rotation = Matrix4X4.CreateRotationZ(radians); - Matrix4X4 undoTransform = SelectedMeshGroupTransform; - SelectedMeshGroupTransform = PlatingHelper.ApplyAtCenter(SelectedMeshGroup, SelectedMeshGroupTransform, rotation); - PlatingHelper.PlaceMeshGroupOnBed(MeshGroups, MeshGroupTransforms, SelectedMeshGroupIndex); - UndoBuffer.Add(new TransformUndoCommand(this, SelectedMeshGroupIndex, undoTransform, SelectedMeshGroupTransform)); + Matrix4X4 undoTransform = Scene.SelectedItem.Matrix; + Scene.SelectedItem.Matrix = PlatingHelper.ApplyAtCenter(Scene.SelectedItem, rotation); + UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix)); PartHasBeenChanged(); Invalidate(); } @@ -1242,12 +1475,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow layFlatButton.Click += (s, e) => { - if (SelectedMeshGroupIndex != -1) + if (Scene.HasSelection) { - Matrix4X4 undoTransform = SelectedMeshGroupTransform; - MakeLowestFaceFlat(SelectedMeshGroupIndex); - PlatingHelper.PlaceMeshGroupOnBed(MeshGroups, MeshGroupTransforms, SelectedMeshGroupIndex); - UndoBuffer.Add(new TransformUndoCommand(this, SelectedMeshGroupIndex, undoTransform, SelectedMeshGroupTransform)); + Matrix4X4 undoTransform = Scene.SelectedItem.Matrix; + MakeLowestFaceFlat(Scene.SelectedItem); + UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix)); PartHasBeenChanged(); Invalidate(); } @@ -1262,7 +1494,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow TupleList> buttonList = new TupleList>(); buttonList.Add("Save".Localize(), () => { - MergeAndSavePartsToCurrentMeshFile(); + if(printItemWrapper == null) + { + UiThread.RunOnIdle(OpenSaveAsWindow); + } + else + { + SaveChanges(null); + } + return true; }); @@ -1274,21 +1514,20 @@ namespace MatterHackers.MatterControl.PartPreviewWindow SplitButtonFactory splitButtonFactory = new SplitButtonFactory(); splitButtonFactory.FixedHeight = 40 * GuiWidget.DeviceScale; + saveButtons = splitButtonFactory.Generate(buttonList, Direction.Up, imageName: "icon_save_32x32.png"); saveButtons.Visible = false; - saveButtons.Margin = new BorderDouble(); saveButtons.VAnchor |= VAnchor.ParentCenter; flowToAddTo.AddChild(saveButtons); } - private bool AllowDragDrop() - { + { if ((!enterEditButtonsContainer.Visible && !doEdittingButtonsContainer.Visible) - || printItemWrapper == null || printItemWrapper.PrintItem.ReadOnly) + || printItemWrapper != null && printItemWrapper.PrintItem.ReadOnly) { return false; } @@ -1341,14 +1580,22 @@ namespace MatterHackers.MatterControl.PartPreviewWindow continueProcessing = true; } - private void ClearBedAndLoadPrintItemWrapper(PrintItemWrapper printItemWrapper) + public async Task ClearBedAndLoadPrintItemWrapper(PrintItemWrapper newPrintItem, bool switchToEditingMode = false) { - SwitchStateToNotEditing(); + if(switchToEditingMode) + { + SwitchStateToEditing(); + } + else + { + SwitchStateToNotEditing(); + } - MeshGroups.Clear(); - MeshGroupExtraData.Clear(); - MeshGroupTransforms.Clear(); - if (printItemWrapper != null) + Scene.ModifyChildren(children => children.Clear()); + + PrintItemWrapper.FileHasChanged.UnregisterEvent(ReloadMeshIfChangeExternaly, ref unregisterEvents); + + if (newPrintItem != null) { // remove it first to make sure we don't double add it PrintItemWrapper.FileHasChanged.UnregisterEvent(ReloadMeshIfChangeExternaly, ref unregisterEvents); @@ -1366,18 +1613,23 @@ namespace MatterHackers.MatterControl.PartPreviewWindow bedCenter = ActiveSliceSettings.Instance.GetValue(SettingsKey.print_center); } - meshViewerWidget.LoadMesh(printItemWrapper.FileLocation, doCentering, bedCenter); + await meshViewerWidget.LoadItemIntoScene(newPrintItem.FileLocation, doCentering, bedCenter, newPrintItem.Name); + + Invalidate(); } + this.printItemWrapper = newPrintItem; + + PartHasBeenChanged(); partHasBeenEdited = false; } private void CreateOptionsContent() { - AddRotateControls(rotateOptionContainer); + AddRotateControls(Sidebar.rotateOptionContainer); } - private void CreateRenderTypeRadioButtons(FlowLayoutWidget viewOptionContainer) + internal void CreateRenderTypeRadioButtons(FlowLayoutWidget viewOptionContainer) { string renderTypeString = UserSettings.Instance.get(UserSettingsKey.defaultRenderSetting); if (renderTypeString == null) @@ -1400,325 +1652,250 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } { - RadioButton renderTypeShaded = new RadioButton("Shaded".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); - renderTypeShaded.Checked = (meshViewerWidget.RenderType == RenderTypes.Shaded); + RadioButton renderTypeCheckBox = new RadioButton("Shaded".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); + renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Shaded); - renderTypeShaded.CheckedStateChanged += (sender, e) => + renderTypeCheckBox.CheckedStateChanged += (sender, e) => { - meshViewerWidget.RenderType = RenderTypes.Shaded; - UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString()); + if (renderTypeCheckBox.Checked) + { + meshViewerWidget.RenderType = RenderTypes.Shaded; + UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString()); + } }; - viewOptionContainer.AddChild(renderTypeShaded); + viewOptionContainer.AddChild(renderTypeCheckBox); } { - RadioButton renderTypeOutlines = new RadioButton("Outlines".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); - renderTypeOutlines.Checked = (meshViewerWidget.RenderType == RenderTypes.Outlines); - renderTypeOutlines.CheckedStateChanged += (sender, e) => + RadioButton renderTypeCheckBox = new RadioButton("Outlines".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); + renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Outlines); + renderTypeCheckBox.CheckedStateChanged += (sender, e) => { - meshViewerWidget.RenderType = RenderTypes.Outlines; - UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString()); + if (renderTypeCheckBox.Checked) + { + meshViewerWidget.RenderType = RenderTypes.Outlines; + UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString()); + } }; - viewOptionContainer.AddChild(renderTypeOutlines); + viewOptionContainer.AddChild(renderTypeCheckBox); } { - RadioButton renderTypePolygons = new RadioButton("Polygons".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); - renderTypePolygons.Checked = (meshViewerWidget.RenderType == RenderTypes.Polygons); - renderTypePolygons.CheckedStateChanged += (sender, e) => + RadioButton renderTypeCheckBox = new RadioButton("Polygons".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); + renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Polygons); + renderTypeCheckBox.CheckedStateChanged += (sender, e) => { - meshViewerWidget.RenderType = RenderTypes.Polygons; - UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString()); + if (renderTypeCheckBox.Checked) + { + meshViewerWidget.RenderType = RenderTypes.Polygons; + UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString()); + } }; - viewOptionContainer.AddChild(renderTypePolygons); + viewOptionContainer.AddChild(renderTypeCheckBox); + } + + { + RadioButton renderTypeCheckBox = new RadioButton("Overhang".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); + renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Overhang); + + renderTypeCheckBox.CheckedStateChanged += (sender, e) => + { + if (renderTypeCheckBox.Checked) + { + meshViewerWidget.RenderType = RenderTypes.Overhang; + UserSettings.Instance.set("defaultRenderSetting", meshViewerWidget.RenderType.ToString()); + foreach (var meshAndTransform in Scene.VisibleMeshes(Matrix4X4.Identity)) + { + meshAndTransform.MeshData.MarkAsChanged(); + // change the color to be the right thing + GLMeshTrianglePlugin glMeshPlugin = GLMeshTrianglePlugin.Get(meshAndTransform.MeshData, (faceEdge) => + { + Vector3 normal = faceEdge.containingFace.normal; + normal = Vector3.TransformVector(normal, meshAndTransform.Matrix).GetNormal(); + VertexColorData colorData = new VertexColorData(); + + double startColor = 223.0 / 360.0; + double endColor = 5.0 / 360.0; + double delta = endColor - startColor; + + RGBA_Bytes color = RGBA_Floats.FromHSL(startColor, .99, .49).GetAsRGBA_Bytes(); + if (normal.z < 0) + { + color = RGBA_Floats.FromHSL(startColor - delta * normal.z, .99, .49).GetAsRGBA_Bytes(); + } + + colorData.red = color.red; + colorData.green = color.green; + colorData.blue = color.blue; + return colorData; + }); + } + } + else + { + foreach (var meshTransform in Scene.VisibleMeshes(Matrix4X4.Identity)) + { + // turn off the overhang colors + } + } + }; + + viewOptionContainer.AddChild(renderTypeCheckBox); } } - private FlowLayoutWidget CreateRightButtonPanel(double buildHeight) + public List objectEditors = new List(); + + public Dictionary> objectEditorsByType = new Dictionary>(); + + private void Scene_SelectionChanged(object sender, EventArgs e) { - FlowLayoutWidget buttonRightPanel = new FlowLayoutWidget(FlowDirection.TopToBottom); - buttonRightPanel.Width = 200; - - // put in undo redo - if(true) // this will not be enabled until the new scene_bundle gets merged + if (!Scene.HasSelection) { - FlowLayoutWidget undoRedoButtons = new FlowLayoutWidget() - { - VAnchor = VAnchor.FitToChildren | VAnchor.ParentTop, - HAnchor = HAnchor.FitToChildren | HAnchor.ParentCenter, - }; - double oldWidth = WhiteButtonFactory.FixedWidth; - WhiteButtonFactory.FixedWidth = WhiteButtonFactory.FixedWidth / 2; - Button undoButton = WhiteButtonFactory.Generate("Undo".Localize(), centerText: true); - undoButton.Name = "3D View Undo"; - undoButton.Enabled = false; - undoButton.Click += (sender, e) => - { - UndoBuffer.Undo(); - }; - undoRedoButtons.AddChild(undoButton); - - Button redoButton = WhiteButtonFactory.Generate("Redo".Localize(), centerText: true); - redoButton.Name = "3D View Redo"; - redoButton.Enabled = false; - redoButton.Click += (sender, e) => - { - UndoBuffer.Redo(); - }; - undoRedoButtons.AddChild(redoButton); - buttonRightPanel.AddChild(undoRedoButtons); - - UndoBuffer.Changed += (sender, e) => - { - undoButton.Enabled = UndoBuffer.UndoCount > 0; - redoButton.Enabled = UndoBuffer.RedoCount > 0; - }; - WhiteButtonFactory.FixedWidth = oldWidth; + selectedObjectPanel.RemoveAllChildren(); + return; } + var selectedItem = Scene.SelectedItem; + + HashSet mappedEditors; + objectEditorsByType.TryGetValue(selectedItem.GetType(), out mappedEditors); + + if(mappedEditors == null) { - BorderDouble buttonMargin = new BorderDouble(top: 3); - - expandRotateOptions = ExpandMenuOptionFactory.GenerateCheckBoxButton( - "Rotate".Localize().ToUpper(), - View3DWidget.ArrowRight, - View3DWidget.ArrowDown); - expandRotateOptions.Margin = new BorderDouble(bottom: 2); - buttonRightPanel.AddChild(expandRotateOptions); - expandRotateOptions.CheckedStateChanged += expandRotateOptions_CheckedStateChanged; - - rotateOptionContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); - rotateOptionContainer.HAnchor = HAnchor.ParentLeftRight; - rotateOptionContainer.Visible = false; - buttonRightPanel.AddChild(rotateOptionContainer); - - buttonRightPanel.AddChild(new ScaleControls(this)); - - buttonRightPanel.AddChild(new MirrorControls(this)); - - PluginFinder SideBarPlugins = new PluginFinder(); - foreach (SideBarPlugin plugin in SideBarPlugins.Plugins) + foreach(var editor in objectEditorsByType) { - buttonRightPanel.AddChild(plugin.CreateSideBarTool(this)); - } - - // put in the material options - int numberOfExtruders = ActiveSliceSettings.Instance.GetValue(SettingsKey.extruder_count); - - expandMaterialOptions = ExpandMenuOptionFactory.GenerateCheckBoxButton("Materials".Localize().ToUpper(), - View3DWidget.ArrowRight, - View3DWidget.ArrowDown); - expandMaterialOptions.Margin = new BorderDouble(bottom: 2); - expandMaterialOptions.CheckedStateChanged += expandMaterialOptions_CheckedStateChanged; - - if (numberOfExtruders > 1) - { - buttonRightPanel.AddChild(expandMaterialOptions); - - materialOptionContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); - materialOptionContainer.HAnchor = HAnchor.ParentLeftRight; - materialOptionContainer.Visible = false; - - buttonRightPanel.AddChild(materialOptionContainer); - AddMaterialControls(materialOptionContainer); - } - - // put in the view options - { - expandViewOptions = ExpandMenuOptionFactory.GenerateCheckBoxButton("Display".Localize().ToUpper(), - View3DWidget.ArrowRight, - View3DWidget.ArrowDown); - expandViewOptions.Margin = new BorderDouble(bottom: 2); - buttonRightPanel.AddChild(expandViewOptions); - expandViewOptions.CheckedStateChanged += expandViewOptions_CheckedStateChanged; - - viewOptionContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); - viewOptionContainer.HAnchor = HAnchor.ParentLeftRight; - viewOptionContainer.Padding = new BorderDouble(left: 4); - viewOptionContainer.Visible = false; + if (selectedItem.GetType().IsSubclassOf(editor.Key)) { - CheckBox showBedCheckBox = new CheckBox("Show Print Bed".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); - showBedCheckBox.Checked = true; - showBedCheckBox.CheckedStateChanged += (sender, e) => - { - meshViewerWidget.RenderBed = showBedCheckBox.Checked; - }; - viewOptionContainer.AddChild(showBedCheckBox); - - if (buildHeight > 0) - { - CheckBox showBuildVolumeCheckBox = new CheckBox("Show Print Area".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); - showBuildVolumeCheckBox.Checked = false; - showBuildVolumeCheckBox.Margin = new BorderDouble(bottom: 5); - showBuildVolumeCheckBox.CheckedStateChanged += (sender, e) => - { - meshViewerWidget.RenderBuildVolume = showBuildVolumeCheckBox.Checked; - }; - viewOptionContainer.AddChild(showBuildVolumeCheckBox); - } - - if (UserSettings.Instance.IsTouchScreen) - { - UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, RenderTypes.Shaded.ToString()); - } - else - { - CreateRenderTypeRadioButtons(viewOptionContainer); - } + mappedEditors = editor.Value; + break; } - buttonRightPanel.AddChild(viewOptionContainer); } - - GuiWidget verticalSpacer = new GuiWidget(); - verticalSpacer.VAnchor = VAnchor.ParentBottomTop; - buttonRightPanel.AddChild(verticalSpacer); - - AddGridSnapSettings(buttonRightPanel); } - buttonRightPanel.Padding = new BorderDouble(6, 6); - buttonRightPanel.Margin = new BorderDouble(0, 1); - buttonRightPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - buttonRightPanel.VAnchor = VAnchor.ParentBottomTop; + editorPanel = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + VAnchor = VAnchor.FitToChildren + }; - return buttonRightPanel; + if (mappedEditors != null) + { + var dropDownList = new DropDownList("", maxHeight: 300) + { + Margin = new BorderDouble(0, 3) + }; + + foreach (IObject3DEditor editor in mappedEditors) + { + MenuItem menuItem = dropDownList.AddItem(editor.Name); + menuItem.Selected += (s, e2) => + { + ShowObjectEditor(editor); + }; + } + + selectedObjectPanel.RemoveAllChildren(); + selectedObjectPanel.AddChild(dropDownList); + selectedObjectPanel.AddChild(editorPanel); + + // Select the active editor or fall back to the first if not found + IObject3DEditor activeEditor = (from editor in mappedEditors + let type = editor.GetType() + where type.Name == selectedItem.ActiveEditor + select editor).FirstOrDefault(); + + if(activeEditor == null) + { + activeEditor = mappedEditors.First(); + } + + int selectedIndex = 0; + for(int i = 0; i < dropDownList.MenuItems.Count; i++) + { + if(dropDownList.MenuItems[i].Text == activeEditor.Name) + { + selectedIndex = i; + break; + } + } + + dropDownList.SelectedIndex = selectedIndex; + + ShowObjectEditor(activeEditor); + } + } + + private void ShowObjectEditor(IObject3DEditor editor) + { + + editorPanel.CloseAllChildren(); + var newEditor = editor.Create(Scene.SelectedItem, this); + editorPanel.AddChild(newEditor); } private void DeleteSelectedMesh() { - // don't ever delete the last mesh - if (SelectedMeshGroupIndex != -1 - && MeshGroups.Count > 1) + if (Scene.HasSelection && Scene.Children.Count > 1) { - int removingIndex = SelectedMeshGroupIndex; - UndoBuffer.Add(new DeleteUndoCommand(this, removingIndex)); + // Create and perform the delete operation + var deleteOperation = new DeleteCommand(this, Scene.SelectedItem); + deleteOperation.Do(); - MeshGroups.RemoveAt(removingIndex); - MeshGroupExtraData.RemoveAt(removingIndex); - MeshGroupTransforms.RemoveAt(removingIndex); - this.SelectedMeshGroupIndex = -1; - PartHasBeenChanged(); + // Store the operation for undo/redo + UndoBuffer.Add(deleteOperation); } } - private void ExitEditingAndSaveIfRequired(bool response) + private void DrawStuffForSelectedPart(Graphics2D graphics2D) { - if (response == true) + if (Scene.HasSelection) { - MergeAndSavePartsToCurrentMeshFile(SwitchStateToNotEditing); + AxisAlignedBoundingBox selectedBounds = Scene.SelectedItem.GetAxisAlignedBoundingBox(Scene.SelectedItem.Matrix); + Vector3 boundsCenter = selectedBounds.Center; + Vector3 centerTop = new Vector3(boundsCenter.x, boundsCenter.y, selectedBounds.maxXYZ.z); + + Vector2 centerTopScreenPosition = meshViewerWidget.TrackballTumbleWidget.GetScreenPosition(centerTop); + centerTopScreenPosition = meshViewerWidget.TransformToParentSpace(this, centerTopScreenPosition); + //graphics2D.Circle(screenPosition.x, screenPosition.y, 5, RGBA_Bytes.Cyan); + + PathStorage zArrow = new PathStorage(); + zArrow.MoveTo(-6, -2); + zArrow.curve3(0, -4); + zArrow.LineTo(6, -2); + zArrow.LineTo(0, 12); + zArrow.LineTo(-6, -2); + + VertexSourceApplyTransform translate = new VertexSourceApplyTransform(zArrow, Affine.NewTranslation(centerTopScreenPosition)); + + //graphics2D.Render(translate, RGBA_Bytes.Black); + } + } + + private void ExitEditingAndSaveIfRequested(bool userResponseYesSave) + { + if (userResponseYesSave) + { + SaveChanges(null, SwitchStateToNotEditing); } else { + // Discard changes in scene, revert back to original state SwitchStateToNotEditing(); + // and reload the part ClearBedAndLoadPrintItemWrapper(printItemWrapper); } } - private void expandMaterialOptions_CheckedStateChanged(object sender, EventArgs e) - { - if (expandMaterialOptions.Checked == true) - { - expandRotateOptions.Checked = false; - expandViewOptions.Checked = false; - } - materialOptionContainer.Visible = expandMaterialOptions.Checked; - } - - private void expandRotateOptions_CheckedStateChanged(object sender, EventArgs e) - { - if (rotateOptionContainer.Visible != expandRotateOptions.Checked) - { - if (expandRotateOptions.Checked == true) - { - expandViewOptions.Checked = false; - expandMaterialOptions.Checked = false; - } - rotateOptionContainer.Visible = expandRotateOptions.Checked; - } - } - - private void expandViewOptions_CheckedStateChanged(object sender, EventArgs e) - { - if (viewOptionContainer.Visible != expandViewOptions.Checked) - { - if (expandViewOptions.Checked == true) - { - expandRotateOptions.Checked = false; - expandMaterialOptions.Checked = false; - } - viewOptionContainer.Visible = expandViewOptions.Checked; - } - } - - IPrimitive allObjects; - private bool FindMeshGroupHitPosition(Vector2 screenPosition, out int meshHitIndex, ref IntersectInfo info) - { - meshHitIndex = 0; - if (MeshGroupExtraData.Count == 0 || MeshGroupExtraData[0].meshTraceableData == null) - { - return false; - } - - List mesheTraceables = new List(); - for (int i = 0; i < MeshGroupExtraData.Count; i++) - { - foreach (IPrimitive traceData in MeshGroupExtraData[i].meshTraceableData) - { - mesheTraceables.Add(new Transform(traceData, MeshGroupTransforms[i])); - } - } - allObjects = BoundingVolumeHierarchy.CreateNewHierachy(mesheTraceables, 0); - - Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, screenPosition); - Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayFromScreen(meshViewerWidgetScreenPosition); - info = allObjects.GetClosestIntersection(ray); - if (info != null) - { - CurrentSelectInfo.PlaneDownHitPos = info.hitPosition; - CurrentSelectInfo.LastMoveDelta = new Vector3(); - - for (int i = 0; i < MeshGroupExtraData.Count; i++) - { - List insideBounds = new List(); - foreach (IPrimitive traceData in MeshGroupExtraData[i].meshTraceableData) - { - traceData.GetContained(insideBounds, info.closestHitObject.GetAxisAlignedBoundingBox()); - } - if (insideBounds.Contains(info.closestHitObject)) - { - meshHitIndex = i; - return true; - } - } - } - - return false; - } - - public GuiWidget GenerateHorizontalRule() - { - GuiWidget horizontalRule = new GuiWidget(); - horizontalRule.Height = 1; - horizontalRule.Margin = new BorderDouble(0, 1, 0, 3); - horizontalRule.HAnchor = HAnchor.ParentLeftRight; - horizontalRule.BackgroundColor = new RGBA_Bytes(255, 255, 255, 200); - return horizontalRule; - } - private async void LoadAndAddPartsToPlate(string[] filesToLoad) { - if (MeshGroups.Count > 0 && filesToLoad != null && filesToLoad.Length > 0) + if (Scene.HasChildren && filesToLoad != null && filesToLoad.Length > 0) { - string loadingPartLabel = "Loading Parts".Localize(); - string loadingPartLabelFull = "{0}:".FormatWith(loadingPartLabel); - processingProgressControl.ProcessType = loadingPartLabelFull; + processingProgressControl.ProcessType = "Loading Parts".Localize() + ":"; processingProgressControl.Visible = true; processingProgressControl.PercentComplete = 0; LockEditControls(); - PushMeshGroupDataToAsynchLists(TraceInfoOpperation.DO_COPY); - await Task.Run(() => loadAndAddPartsToPlate(filesToLoad)); if (HasBeenClosed) @@ -1729,15 +1906,14 @@ namespace MatterHackers.MatterControl.PartPreviewWindow UnlockEditControls(); PartHasBeenChanged(); - bool addingOnlyOneItem = asyncMeshGroups.Count == MeshGroups.Count + 1; + bool addingOnlyOneItem = Scene.Children.Count == Scene.Children.Count + 1; - if (MeshGroups.Count > 0) + if (Scene.HasChildren) { - PullMeshGroupDataFromAsynchLists(); if (addingOnlyOneItem) { // if we are only adding one part to the plate set the selection to it - SelectedMeshGroupIndex = asyncMeshGroups.Count - 1; + Scene.SelectLastChild(); } } } @@ -1747,12 +1923,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - List filesToLoad = new List(); - if (filesToLoadIncludingZips != null && filesToLoadIncludingZips.Length > 0) + if (filesToLoadIncludingZips?.Any() == true) { - for (int i = 0; i < filesToLoadIncludingZips.Length; i++) + List filesToLoad = new List(); + foreach (string loadedFileName in filesToLoadIncludingZips) { - string loadedFileName = filesToLoadIncludingZips[i]; string extension = Path.GetExtension(loadedFileName).ToUpper(); if ((extension != "" && MeshFileIo.ValidFileExtensions().Contains(extension))) { @@ -1760,8 +1935,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } else if (extension == ".ZIP") { - ProjectFileHandler project = new ProjectFileHandler(null); - List partFiles = project.ImportFromProjectArchive(loadedFileName); + List partFiles = ProjectFileHandler.ImportFromProjectArchive(loadedFileName); if (partFiles != null) { foreach (PrintItem part in partFiles) @@ -1773,12 +1947,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } string progressMessage = "Loading Parts...".Localize(); + double ratioPerFile = 1.0 / filesToLoad.Count; double currentRatioDone = 0; - for (int i = 0; i < filesToLoad.Count; i++) + + var itemCache = new Dictionary(); + + foreach (string loadedFileName in filesToLoad) { - string loadedFileName = filesToLoad[i]; - List loadedMeshGroups = MeshFileIo.Load(Path.GetFullPath(loadedFileName), (double progress0To1, string processingState, out bool continueProcessing) => + IObject3D newItem = Object3D.Load(loadedFileName, itemCache, (double progress0To1, string processingState, out bool continueProcessing) => { continueProcessing = !this.HasBeenClosed; double ratioAvailable = (ratioPerFile * .5); @@ -1790,31 +1967,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { return; } - if (loadedMeshGroups != null) + + if (newItem != null) { - double ratioPerSubMesh = ratioPerFile / loadedMeshGroups.Count; - double subMeshRatioDone = 0; + Scene.ModifyChildren(children => children.Add(newItem)); - for (int subMeshIndex = 0; subMeshIndex < loadedMeshGroups.Count; subMeshIndex++) - { - MeshGroup meshGroup = loadedMeshGroups[subMeshIndex]; + PlatingHelper.MoveToOpenPosition(newItem, this.Scene); - PlatingHelper.FindPositionForGroupAndAddToPlate(meshGroup, Matrix4X4.Identity, asyncPlatingDatas, asyncMeshGroups, asyncMeshGroupTransforms); - if (HasBeenClosed) - { - return; - } - PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, asyncMeshGroups.Count - 1, (double progress0To1, string processingState, out bool continueProcessing) => - { - continueProcessing = !this.HasBeenClosed; - double ratioAvailable = (ratioPerFile * .5); - // done outer loop + done this loop +first 1/2 (load)+ this part * ratioAvailable - double currentRatio = currentRatioDone + subMeshRatioDone + ratioAvailable + progress0To1 * ratioPerSubMesh; - ReportProgressChanged(currentRatio, progressMessage, out continueProcessing); - }); - - subMeshRatioDone += ratioPerSubMesh; - } + // TODO: There should be a batch insert so you can undo large 'add to scene' operations in one go + //this.InsertNewItem(tempScene); } currentRatioDone += ratioPerFile; @@ -1822,7 +1983,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } } - private void LockEditControls() + public void LockEditControls() { viewIsInEditModePreLock = doEdittingButtonsContainer.Visible; enterEditButtonsContainer.Visible = false; @@ -1839,24 +2000,30 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } } - private void MakeLowestFaceFlat(int indexToLayFlat) + private void MakeLowestFaceFlat(IObject3D objectToLayFlatGroup) { - Vertex lowestVertex = MeshGroups[indexToLayFlat].Meshes[0].Vertices[0]; + Matrix4X4 objectToWold = objectToLayFlatGroup.Matrix; + IObject3D objectToLayFlat = objectToLayFlatGroup.Children[0]; - Vector3 lowestVertexPosition = Vector3.Transform(lowestVertex.Position, MeshGroupTransforms[indexToLayFlat]); - Mesh meshToLayFlat = null; - foreach (Mesh meshToCheck in MeshGroups[indexToLayFlat].Meshes) + Vertex lowestVertex = objectToLayFlat.Mesh.Vertices[0]; + + Vector3 lowestVertexPosition = Vector3.Transform(lowestVertex.Position, objectToWold); + + IObject3D itemToLayFlat = null; + + // Process each child, checking for the lowest vertex + foreach (IObject3D itemToCheck in objectToLayFlat.Children.Where(child => child.Mesh != null)) { // find the lowest point on the model - for (int testIndex = 1; testIndex < meshToCheck.Vertices.Count; testIndex++) + for (int testIndex = 1; testIndex < itemToCheck.Mesh.Vertices.Count; testIndex++) { - Vertex vertex = meshToCheck.Vertices[testIndex]; - Vector3 vertexPosition = Vector3.Transform(vertex.Position, MeshGroupTransforms[indexToLayFlat]); + Vertex vertex = itemToCheck.Mesh.Vertices[testIndex]; + Vector3 vertexPosition = Vector3.Transform(vertex.Position, objectToWold); if (vertexPosition.z < lowestVertexPosition.z) { - lowestVertex = meshToCheck.Vertices[testIndex]; + lowestVertex = itemToCheck.Mesh.Vertices[testIndex]; lowestVertexPosition = vertexPosition; - meshToLayFlat = meshToCheck; + itemToLayFlat = itemToCheck; } } } @@ -1871,7 +2038,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { if (faceVertex != lowestVertex) { - Vector3 faceVertexPosition = Vector3.Transform(faceVertex.Position, MeshGroupTransforms[indexToLayFlat]); + Vector3 faceVertexPosition = Vector3.Transform(faceVertex.Position, objectToWold); Vector3 pointRelLowest = faceVertexPosition - lowestVertexPosition; double xLeg = new Vector2(pointRelLowest.x, pointRelLowest.y).Length; double yLeg = pointRelLowest.z; @@ -1893,7 +2060,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow List faceVertexes = new List(); foreach (Vertex vertex in faceToLayFlat.Vertices()) { - Vector3 vertexPosition = Vector3.Transform(vertex.Position, MeshGroupTransforms[indexToLayFlat]); + Vector3 vertexPosition = Vector3.Transform(vertex.Position, objectToWold); faceVertexes.Add(vertexPosition); maxDistFromLowestZ = Math.Max(maxDistFromLowestZ, vertexPosition.z - lowestVertexPosition.z); } @@ -1909,7 +2076,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow Matrix4X4 partLevelMatrix = Matrix4X4.CreateRotation(rotation); // rotate it - SelectedMeshGroupTransform = PlatingHelper.ApplyAtCenter(SelectedMeshGroup, SelectedMeshGroupTransform, partLevelMatrix); + objectToLayFlatGroup.Matrix = PlatingHelper.ApplyAtCenter(objectToLayFlatGroup, partLevelMatrix); PartHasBeenChanged(); Invalidate(); @@ -1918,205 +2085,86 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public static Regex fileNameNumberMatch = new Regex("\\(\\d+\\)", RegexOptions.Compiled); - private void MergeAndSavePartsDoWork(SaveAsWindow.SaveAsReturnInfo returnInfo) - { - if (returnInfo != null) - { - PrintItem printItem = new PrintItem(); - printItem.Name = returnInfo.newName; - printItem.FileLocation = Path.GetFullPath(returnInfo.fileNameAndPath); - printItemWrapper = new PrintItemWrapper(printItem, returnInfo.destinationLibraryProvider.GetProviderLocator()); - } + private GuiWidget selectedObjectPanel; + private FlowLayoutWidget editorPanel; - // we sent the data to the async lists but we will not pull it back out (only use it as a temp holder). - PushMeshGroupDataToAsynchLists(TraceInfoOpperation.DO_COPY); - - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - try - { - // push all the transforms into the meshes - for (int i = 0; i < asyncMeshGroups.Count; i++) - { - asyncMeshGroups[i].Transform(asyncMeshGroupTransforms[i]); - - bool continueProcessing; - ReportProgressChanged((i + 1) * .4 / asyncMeshGroups.Count, "", out continueProcessing); - } - - string[] metaData = { "Created By", "MatterControl", "BedPosition", "Absolute" }; - - MeshOutputSettings outputInfo = new MeshOutputSettings(MeshOutputSettings.OutputType.Binary, metaData); - - // If null we are replacing a file from the current print item wrapper - if (returnInfo == null) - { - var fileInfo = new FileInfo(printItemWrapper.FileLocation); - - bool requiresTypeChange = !fileInfo.Extension.Equals(".amf", StringComparison.OrdinalIgnoreCase); - if (requiresTypeChange && !printItemWrapper.UseIncrementedNameDuringTypeChange) - { - // Not using incremented file name, simply change to AMF - printItemWrapper.FileLocation = Path.ChangeExtension(printItemWrapper.FileLocation, ".amf"); - } - else if (requiresTypeChange) - { - string newFileName; - string incrementedFileName; - - // Switching from .stl, .obj or similar to AMF. Save the file and update the - // the filename with an incremented (n) value to reflect the extension change in the UI - string fileName = Path.GetFileNameWithoutExtension(fileInfo.Name); - - // Drop bracketed number sections from our source filename to ensure we don't generate something like "file (1) (1).amf" - if (fileName.Contains("(")) - { - fileName = fileNameNumberMatch.Replace(fileName, "").Trim(); - } - - // Generate and search for an incremented file name until no match is found at the target directory - int foundCount = 0; - do - { - newFileName = string.Format("{0} ({1})", fileName, ++foundCount); - incrementedFileName = Path.Combine(fileInfo.DirectoryName, newFileName + ".amf"); - - // Continue incrementing while any matching file exists - } while (Directory.GetFiles(fileInfo.DirectoryName, newFileName + ".*").Any()); - - // Change the FileLocation to the new AMF file - printItemWrapper.FileLocation = incrementedFileName; - } - - try - { - // get a new location to save to - string tempFileNameToSaveTo = ApplicationDataStorage.Instance.GetTempFileName("amf"); - - // save to the new temp location - bool savedSuccessfully = MeshFileIo.Save(asyncMeshGroups, tempFileNameToSaveTo, outputInfo, ReportProgressChanged); - - // Swap out the files if the save operation completed successfully - if (savedSuccessfully && File.Exists(tempFileNameToSaveTo)) - { - // Ensure the target path is clear - if(File.Exists(printItemWrapper.FileLocation)) - { - File.Delete(printItemWrapper.FileLocation); - } - - // Move the newly saved file back into place - File.Move(tempFileNameToSaveTo, printItemWrapper.FileLocation); - - // Once the file is swapped back into place, update the PrintItem to account for extension change - printItemWrapper.PrintItem.Commit(); - } - } - catch(Exception ex) - { - Trace.WriteLine("Error saving file: ", ex.Message); - } - } - else // we are saving a new file and it will not exist until we are done - { - MeshFileIo.Save(asyncMeshGroups, printItemWrapper.FileLocation, outputInfo, ReportProgressChanged); - } - - // Wait for a second to report the file changed to give the OS a chance to finish closing it. - UiThread.RunOnIdle(printItemWrapper.ReportFileChange, 3); - - if (returnInfo != null - && returnInfo.destinationLibraryProvider != null) - { - // save this part to correct library provider - LibraryProvider libraryToSaveTo = returnInfo.destinationLibraryProvider; - if (libraryToSaveTo != null) - { - libraryToSaveTo.AddItem(printItemWrapper); - libraryToSaveTo.Dispose(); - } - } - else // we have already saved it and the library should pick it up - { - } - - saveSucceded = true; - } - catch (System.UnauthorizedAccessException e2) - { - Debug.Print(e2.Message); - GuiWidget.BreakInDebugger(); - saveSucceded = false; - UiThread.RunOnIdle(() => - { - //Do something special when unauthorized? - StyledMessageBox.ShowMessageBox(null, "Oops! Unable to save changes.", "Unable to save"); - }); - } - catch (Exception e) - { - Debug.Print(e.Message); - GuiWidget.BreakInDebugger(); - saveSucceded = false; - UiThread.RunOnIdle(() => - { - StyledMessageBox.ShowMessageBox(null, "Oops! Unable to save changes.", "Unable to save"); - }); - } - } - - private void MergeAndSavePartsDoCompleted() - { - if (HasBeenClosed) - { - return; - } - UnlockEditControls(); - - // NOTE: we do not pull the data back out of the async lists. - if (saveSucceded) - { - saveButtons.Visible = false; - } - - if (afterSaveCallback != null) - { - afterSaveCallback(); - } - } - - private async void MergeAndSavePartsToCurrentMeshFile(Action eventToCallAfterSave = null) + private async void SaveChanges(SaveAsWindow.SaveAsReturnInfo returnInfo = null, Action eventToCallAfterSave = null) { editorThatRequestedSave = true; afterSaveCallback = eventToCallAfterSave; - if (MeshGroups.Count > 0) + if (Scene.HasChildren) { - string progressSavingPartsLabel = "Saving".Localize(); - string progressSavingPartsLabelFull = "{0}:".FormatWith(progressSavingPartsLabel); - processingProgressControl.ProcessType = progressSavingPartsLabelFull; + processingProgressControl.ProcessType = "Saving".Localize() + ":"; processingProgressControl.Visible = true; processingProgressControl.PercentComplete = 0; + LockEditControls(); - await Task.Run(() => MergeAndSavePartsDoWork(null)); - MergeAndSavePartsDoCompleted(); - } - } + // Perform the actual save operation + await Task.Run(() => + { + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - private async void MergeAndSavePartsToNewMeshFile(SaveAsWindow.SaveAsReturnInfo returnInfo) - { - editorThatRequestedSave = true; - if (MeshGroups.Count > 0) - { - string progressSavingPartsLabel = "Saving".Localize(); - string progressSavingPartsLabelFull = "{0}:".FormatWith(progressSavingPartsLabel); - processingProgressControl.ProcessType = progressSavingPartsLabelFull; - processingProgressControl.Visible = true; - processingProgressControl.PercentComplete = 0; - LockEditControls(); + try + { + // If null we are replacing a file from the current print item wrapper + if (returnInfo == null) + { + // Only save as .mcx + if (Path.GetExtension(printItemWrapper.FileLocation) != ".mcx") + { + printItemWrapper.FileLocation = Path.ChangeExtension(printItemWrapper.FileLocation, ".mcx"); + } + } + else // Otherwise we are saving a new file + { + printItemWrapper = new PrintItemWrapper( + new PrintItem() + { + Name = returnInfo.newName, + FileLocation = Path.ChangeExtension(returnInfo.fileNameAndPath, ".mcx") + }, + returnInfo.destinationLibraryProvider.GetProviderLocator()); + } - await Task.Run(() => MergeAndSavePartsDoWork(returnInfo)); - MergeAndSavePartsDoCompleted(); + // TODO: Hook up progress reporting + Scene.Save(printItemWrapper.FileLocation, ApplicationDataStorage.Instance.ApplicationLibraryDataPath); + + printItemWrapper.PrintItem.Commit(); + + // Wait for a second to report the file changed to give the OS a chance to finish closing it. + UiThread.RunOnIdle(printItemWrapper.ReportFileChange, 3); + + // Save to the destination provider, otherwise it already exists and has a file monitor + if (returnInfo?.destinationLibraryProvider != null) + { + // save this part to correct library provider + LibraryProvider libraryToSaveTo = returnInfo.destinationLibraryProvider; + if (libraryToSaveTo != null) + { + libraryToSaveTo.AddItem(printItemWrapper); + libraryToSaveTo.Dispose(); + } + } + + saveSucceded = true; + } + catch (Exception ex) + { + Trace.WriteLine("Error saving file: ", ex.Message); + } + }); + + // Post Save cleanup + if (this.HasBeenClosed) + { + return; + } + + UnlockEditControls(); + saveButtons.Visible = !saveSucceded; + afterSaveCallback?.Invoke(); } } @@ -2140,21 +2188,37 @@ namespace MatterHackers.MatterControl.PartPreviewWindow UnlockEditControls(); } - SelectionChanged?.Invoke(this, null); + // Used to be bound to SelectionChanged event that no one was using and that overlapped with Queue SelectionChanged events that already signify this state change. + // Eliminate unnecessary event and restore later if some external caller needs this hook + if (Scene.HasSelection && Scene.SelectedItem.Mesh != null) + { + // TODO: Likely needs to be reviewed as described above and in the context of the scene graph + MeshMaterialData material = MeshMaterialData.Get(Scene.SelectedItem.Mesh); + for (int i = 0; i < extruderButtons.Count; i++) + { + if (material.MaterialIndex - 1 == i) + { + ((RadioButton)extruderButtons[i]).Checked = true; + } + } + } if (openMode == OpenMode.Editing) { - UiThread.RunOnIdle(EnterEditAndCreateSelectionData); + UiThread.RunOnIdle(SwitchStateToEditing); } - - meshViewerWidget.ResetView(); } private bool PartsAreInPrintVolume() { if (ActiveSliceSettings.Instance?.GetValue(SettingsKey.center_part_on_bed) == false) { - AxisAlignedBoundingBox allBounds = MeshViewerWidget.GetAxisAlignedBoundingBox(MeshGroups); + AxisAlignedBoundingBox allBounds = AxisAlignedBoundingBox.Empty; + foreach(var aabb in Scene.Children.Select(item => item.GetAxisAlignedBoundingBox(Matrix4X4.Identity))) + { + allBounds += aabb; + } + bool onBed = allBounds.minXYZ.z > -.001 && allBounds.minXYZ.z < .001; // really close to the bed RectangleDouble bedRect = new RectangleDouble(0, 0, ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_size).x, ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_size).y); bedRect.Offset(ActiveSliceSettings.Instance.GetValue(SettingsKey.print_center) - ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_size) / 2); @@ -2188,12 +2252,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { if (saveAsWindow == null) { - List providerLocator = null; - if (printItemWrapper.SourceLibraryProviderLocator != null) - { - providerLocator = printItemWrapper.SourceLibraryProviderLocator; - } - saveAsWindow = new SaveAsWindow(MergeAndSavePartsToNewMeshFile, providerLocator, true, true); + saveAsWindow = new SaveAsWindow(SaveChanges, printItemWrapper?.SourceLibraryProviderLocator, true, true); saveAsWindow.Closed += SaveAsWindow_Closed; } else @@ -2202,76 +2261,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } } - private void PullMeshGroupDataFromAsynchLists() - { - if (MeshGroups.Count != asyncMeshGroups.Count) - { - PartHasBeenChanged(); - } - - MeshGroups.Clear(); - foreach (MeshGroup meshGroup in asyncMeshGroups) - { - MeshGroups.Add(meshGroup); - } - MeshGroupTransforms.Clear(); - foreach (Matrix4X4 transform in asyncMeshGroupTransforms) - { - MeshGroupTransforms.Add(transform); - } - MeshGroupExtraData.Clear(); - foreach (PlatingMeshGroupData meshData in asyncPlatingDatas) - { - MeshGroupExtraData.Add(meshData); - } - - if (MeshGroups.Count != MeshGroupTransforms.Count - || MeshGroups.Count != MeshGroupExtraData.Count) - { - throw new Exception("These all need to remain in sync."); - } - } - - private void PushMeshGroupDataToAsynchLists(TraceInfoOpperation traceInfoOpperation, ReportProgressRatio reportProgress = null) - { - UiThread.RunOnIdle(() => - { - processingProgressControl.ProgressMessage = "Async Copy"; - }); - asyncMeshGroups.Clear(); - asyncMeshGroupTransforms.Clear(); - for (int meshGroupIndex = 0; meshGroupIndex < MeshGroups.Count; meshGroupIndex++) - { - MeshGroup meshGroup = MeshGroups[meshGroupIndex]; - MeshGroup newMeshGroup = new MeshGroup(); - for (int meshIndex = 0; meshIndex < meshGroup.Meshes.Count; meshIndex++) - { - Mesh mesh = meshGroup.Meshes[meshIndex]; - newMeshGroup.Meshes.Add(Mesh.Copy(mesh)); - } - asyncMeshGroups.Add(newMeshGroup); - asyncMeshGroupTransforms.Add(MeshGroupTransforms[meshGroupIndex]); - } - asyncPlatingDatas.Clear(); - - for (int meshGroupIndex = 0; meshGroupIndex < MeshGroupExtraData.Count; meshGroupIndex++) - { - PlatingMeshGroupData meshData = new PlatingMeshGroupData(); - MeshGroup meshGroup = MeshGroups[meshGroupIndex]; - - if (traceInfoOpperation == TraceInfoOpperation.DO_COPY) - { - meshData.meshTraceableData.AddRange(MeshGroupExtraData[meshGroupIndex].meshTraceableData); - } - - asyncPlatingDatas.Add(meshData); - } - UiThread.RunOnIdle(() => - { - processingProgressControl.ProgressMessage = ""; - }); - } - private void ReloadMeshIfChangeExternaly(Object sender, EventArgs e) { PrintItemWrapper senderItem = sender as PrintItemWrapper; @@ -2322,27 +2311,80 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public override bool InEditMode { - get { return buttonRightPanel.Visible; } + get { return Sidebar != null && Sidebar.Visible; } } private void SwitchStateToNotEditing() { + IsEditing = false; + if (!enterEditButtonsContainer.Visible) { enterEditButtonsContainer.Visible = true; processingProgressControl.Visible = false; - buttonRightPanel.Visible = false; + Sidebar.Visible = false; doEdittingButtonsContainer.Visible = false; viewControls3D.PartSelectVisible = false; if (viewControls3D.ActiveButton == ViewControls3DButtons.PartSelect) { viewControls3D.ActiveButton = ViewControls3DButtons.Rotate; } - SelectedMeshGroupIndex = -1; + + Scene.ModifyChildren(ClearSelectionApplyChanges); } } - private void UnlockEditControls() + internal async void SwitchStateToEditing() + { + if (enterEditButtonsContainer.Visible == true) + { + enterEditButtonsContainer.Visible = false; + } + + this.IsEditing = true; + + viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect; + + processingProgressControl.Visible = true; + LockEditControls(); + viewIsInEditModePreLock = true; + + if (Scene.HasChildren) + { + // CreateSelectionData() + await Task.Run(() => + { + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + processingProgressControl.ProcessType = "Preparing Meshes".Localize() + ":"; + + // Force trace data generation + foreach (var object3D in Scene.Children) + { + object3D.TraceData(); + } + + // TODO: Why were we recreating GLData on edit? + //bool continueProcessing2; + //ReportProgressChanged(1, "Creating GL Data", out continueProcessing2); + //meshViewerWidget.CreateGlDataForMeshes(Scene.Children); + }); + + if (this.HasBeenClosed) + { + return; + } + + Scene.SelectFirstChild(); + } + + Sidebar.Visible = true; + UnlockEditControls(); + viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect; + + Invalidate(); + } + + public void UnlockEditControls() { buttonRightPanelDisabledCover.Visible = false; processingProgressControl.Visible = false; diff --git a/PartPreviewWindow/ViewControls3D.cs b/PartPreviewWindow/ViewControls3D.cs index 90fecba52..e2f648f91 100644 --- a/PartPreviewWindow/ViewControls3D.cs +++ b/PartPreviewWindow/ViewControls3D.cs @@ -39,7 +39,6 @@ using MatterHackers.Agg.ImageProcessing; namespace MatterHackers.MatterControl.PartPreviewWindow { - public enum ViewControls3DButtons { Rotate, @@ -60,6 +59,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private RadioButton scaleButton; private RadioButton partSelectButton; + private EventHandler unregisterEvents; + private int buttonHeight; public event EventHandler ResetView; @@ -123,77 +124,65 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } this.meshViewerWidget = meshViewerWidget; - TextImageButtonFactory textImageButtonFactory = new TextImageButtonFactory(); + var textImageButtonFactory = new TextImageButtonFactory() + { + normalTextColor = ActiveTheme.Instance.PrimaryTextColor, + hoverTextColor = ActiveTheme.Instance.PrimaryTextColor, + disabledTextColor = ActiveTheme.Instance.PrimaryTextColor, + pressedTextColor = ActiveTheme.Instance.PrimaryTextColor, + FixedHeight = buttonHeight, + FixedWidth = buttonHeight, + AllowThemeToAdjustImage = false, + checkedBorderColor = RGBA_Bytes.White + }; - textImageButtonFactory.normalTextColor = ActiveTheme.Instance.PrimaryTextColor; - textImageButtonFactory.hoverTextColor = ActiveTheme.Instance.PrimaryTextColor; - textImageButtonFactory.disabledTextColor = ActiveTheme.Instance.PrimaryTextColor; - textImageButtonFactory.pressedTextColor = ActiveTheme.Instance.PrimaryTextColor; + + string iconPath; - BackgroundColor = new RGBA_Bytes(0, 0, 0, 120); - textImageButtonFactory.FixedHeight = buttonHeight * GuiWidget.DeviceScale; - textImageButtonFactory.FixedWidth = buttonHeight * GuiWidget.DeviceScale; - textImageButtonFactory.AllowThemeToAdjustImage = false; - textImageButtonFactory.checkedBorderColor = RGBA_Bytes.White; - - string resetViewIconPath = Path.Combine("ViewTransformControls", "reset.png"); - resetViewButton = textImageButtonFactory.Generate("", StaticData.Instance.LoadIcon(resetViewIconPath, 32,32).InvertLightness()); + iconPath = Path.Combine("ViewTransformControls", "reset.png"); + resetViewButton = textImageButtonFactory.Generate("", StaticData.Instance.LoadIcon(iconPath,32,32).InvertLightness()); resetViewButton.ToolTipText = "Reset View".Localize(); AddChild(resetViewButton); - resetViewButton.Click += (sender, e) => - { - ResetView?.Invoke(this, null); - }; + resetViewButton.Click += (s, e) => ResetView?.Invoke(this, null); - string rotateIconPath = Path.Combine("ViewTransformControls", "rotate.png"); - rotateButton = textImageButtonFactory.GenerateRadioButton("", StaticData.Instance.LoadIcon(rotateIconPath,32,32)); + iconPath = Path.Combine("ViewTransformControls", "rotate.png"); + rotateButton = textImageButtonFactory.GenerateRadioButton("", StaticData.Instance.LoadIcon(iconPath,32,32)); rotateButton.ToolTipText = "Rotate (Alt + Left Mouse)".Localize(); - rotateButton.Margin = new BorderDouble(3); + rotateButton.Margin = new BorderDouble(3); AddChild(rotateButton); - rotateButton.Click += (sender, e) => - { - this.ActiveButton = ViewControls3DButtons.Rotate; - }; + rotateButton.Click += (s, e) => this.ActiveButton = ViewControls3DButtons.Rotate; - string translateIconPath = Path.Combine("ViewTransformControls", "translate.png"); - translateButton = textImageButtonFactory.GenerateRadioButton("", StaticData.Instance.LoadIcon(translateIconPath,32,32)); + iconPath = Path.Combine("ViewTransformControls", "translate.png"); + translateButton = textImageButtonFactory.GenerateRadioButton("", StaticData.Instance.LoadIcon(iconPath,32,32)); translateButton.ToolTipText = "Move (Shift + Left Mouse)".Localize(); - translateButton.Margin = new BorderDouble(3); + translateButton.Margin = new BorderDouble(3); AddChild(translateButton); - translateButton.Click += (sender, e) => - { - this.ActiveButton = ViewControls3DButtons.Translate; - }; + translateButton.Click += (s, e) => this.ActiveButton = ViewControls3DButtons.Translate; - string scaleIconPath = Path.Combine("ViewTransformControls", "scale.png"); - scaleButton = textImageButtonFactory.GenerateRadioButton("", StaticData.Instance.LoadIcon(scaleIconPath,32,32)); + iconPath = Path.Combine("ViewTransformControls", "scale.png"); + scaleButton = textImageButtonFactory.GenerateRadioButton("", StaticData.Instance.LoadIcon(iconPath,32,32)); scaleButton.ToolTipText = "Zoom (Ctrl + Left Mouse)".Localize(); - scaleButton.Margin = new BorderDouble(3); + scaleButton.Margin = new BorderDouble(3); AddChild(scaleButton); - scaleButton.Click += (sender, e) => - { - this.ActiveButton = ViewControls3DButtons.Scale; - }; + scaleButton.Click += (s, e) => this.ActiveButton = ViewControls3DButtons.Scale; partSelectSeparator = new GuiWidget(2, 32); partSelectSeparator.BackgroundColor = RGBA_Bytes.White; partSelectSeparator.Margin = new BorderDouble(3); AddChild(partSelectSeparator); - string partSelectIconPath = Path.Combine("ViewTransformControls", "partSelect.png"); - partSelectButton = textImageButtonFactory.GenerateRadioButton("", StaticData.Instance.LoadIcon(partSelectIconPath,32,32)); + iconPath = Path.Combine("ViewTransformControls", "partSelect.png"); + partSelectButton = textImageButtonFactory.GenerateRadioButton("", StaticData.Instance.LoadIcon(iconPath,32,32)); partSelectButton.ToolTipText = "Select Part".Localize(); partSelectButton.Margin = new BorderDouble(3); AddChild(partSelectButton); - partSelectButton.Click += (sender, e) => - { - this.ActiveButton = ViewControls3DButtons.PartSelect; - }; + partSelectButton.Click += (s, e) => this.ActiveButton = ViewControls3DButtons.PartSelect; Margin = new BorderDouble(5); HAnchor |= Agg.UI.HAnchor.ParentLeft; VAnchor = Agg.UI.VAnchor.ParentTop; rotateButton.Checked = true; + BackgroundColor = new RGBA_Bytes(0, 0, 0, 120); SetMeshViewerDisplayTheme(); partSelectButton.CheckedStateChanged += SetMeshViewerDisplayTheme; @@ -201,14 +190,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow ActiveTheme.ThemeChanged.RegisterEvent(ThemeChanged, ref unregisterEvents); } - private EventHandler unregisterEvents; - public override void OnClosed(ClosedEventArgs e) { - if (unregisterEvents != null) - { - unregisterEvents(this, null); - } + unregisterEvents?.Invoke(this, null); base.OnClosed(e); } diff --git a/PartPreviewWindow/ViewGcodeBasic.cs b/PartPreviewWindow/ViewGcodeBasic.cs index 016f2fa9e..fadc7e5f4 100644 --- a/PartPreviewWindow/ViewGcodeBasic.cs +++ b/PartPreviewWindow/ViewGcodeBasic.cs @@ -56,7 +56,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private TextWidget gcodeProcessingStateInfoText; private ViewGcodeWidget gcodeViewWidget; - private PrintItemWrapper printItem; + private PrintItemWrapper printItem { get; set; } private bool startedSliceFromGenerateButton = false; private Button generateGCodeButton; private FlowLayoutWidget buttonBottomPanel; @@ -90,13 +90,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private BedShape bedShape; private int sliderWidth; - public ViewGcodeBasic(PrintItemWrapper printItem, Vector3 viewerVolume, Vector2 bedCenter, BedShape bedShape, WindowMode windowMode) + public ViewGcodeBasic(Vector3 viewerVolume, Vector2 bedCenter, BedShape bedShape, WindowMode windowMode) { this.viewerVolume = viewerVolume; this.bedShape = bedShape; this.bedCenter = bedCenter; this.windowMode = windowMode; - this.printItem = printItem; if (UserSettings.Instance.IsTouchScreen) { @@ -110,9 +109,30 @@ namespace MatterHackers.MatterControl.PartPreviewWindow CreateAndAddChildren(); ActiveSliceSettings.SettingChanged.RegisterEvent(CheckSettingChanged, ref unregisterEvents); - ApplicationController.Instance.AdvancedControlsPanelReloading.RegisterEvent((s, e) => ClearGCode(), ref unregisterEvents); + + ApplicationController.Instance.AdvancedControlsPanelReloading.RegisterEvent(RecreateBedAndPartPosition, ref unregisterEvents); + ActiveSliceSettings.ActivePrinterChanged.RegisterEvent(RecreateBedAndPartPosition, ref unregisterEvents); + + ActiveSliceSettings.ActivePrinterChanged.RegisterEvent(CheckSettingChanged, ref unregisterEvents); } + private void RecreateBedAndPartPosition(object sender, EventArgs e) + { + viewerVolume = new Vector3(ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_size), ActiveSliceSettings.Instance.GetValue(SettingsKey.build_height)); + bedShape = ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_shape); + bedCenter = ActiveSliceSettings.Instance.GetValue(SettingsKey.print_center); + + double buildHeight = ActiveSliceSettings.Instance.GetValue(SettingsKey.build_height); + + UiThread.RunOnIdle(() => + { + meshViewerWidget.CreatePrintBed( + viewerVolume, + bedCenter, + bedShape); + }); + } + private void CheckSettingChanged(object sender, EventArgs e) { StringEventArgs stringEvent = e as StringEventArgs; @@ -135,31 +155,62 @@ namespace MatterHackers.MatterControl.PartPreviewWindow || stringEvent.Data == SettingsKey.bed_shape || stringEvent.Data == SettingsKey.center_part_on_bed) { - viewerVolume = new Vector3(ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_size), ActiveSliceSettings.Instance.GetValue(SettingsKey.build_height)); - bedShape = ActiveSliceSettings.Instance.GetValue(SettingsKey.bed_shape); - bedCenter = ActiveSliceSettings.Instance.GetValue(SettingsKey.print_center); - - double buildHeight = ActiveSliceSettings.Instance.GetValue(SettingsKey.build_height); - - UiThread.RunOnIdle(() => - { - meshViewerWidget.CreatePrintBed( - viewerVolume, - bedCenter, - bedShape); - }); + RecreateBedAndPartPosition(null, null); } else if(stringEvent.Data == "extruder_offset") { - ClearGCode(); + Clear3DGCode(); } } } - private void ClearGCode() + public void LoadItem(PrintItemWrapper printItem) { - if (gcodeViewWidget != null - && gcodeViewWidget.gCodeRenderer != null) + this.printItem = printItem; + Clear3DGCode(); + + gcodeDisplayWidget.CloseAllChildren(); + + //firstProcessingMessage = "Loading G-Code...".Localize(); + if (Path.GetExtension(printItem.FileLocation).ToUpper() == ".GCODE") + { + gcodeDisplayWidget.AddChild(CreateGCodeViewWidget(printItem.FileLocation)); + } + else + { + if (File.Exists(printItem.FileLocation)) + { + string gcodePathAndFileName = printItem.GetGCodePathAndFileName(); + bool gcodeFileIsComplete = printItem.IsGCodeFileComplete(gcodePathAndFileName); + + //if (printItem.SlicingHadError) + //{ + // firstProcessingMessage = slicingErrorMessage; + //} + //else + //{ + // firstProcessingMessage = pressGenerateMessage; + //} + + if (File.Exists(gcodePathAndFileName) && gcodeFileIsComplete) + { + gcodeDisplayWidget.AddChild(CreateGCodeViewWidget(gcodePathAndFileName)); + } + + // we only hook these up to make sure we can regenerate the gcode when we want + printItem.SlicingOutputMessage += sliceItem_SlicingOutputMessage; + printItem.SlicingDone += sliceItem_Done; + } + //else + //{ + // firstProcessingMessage = string.Format("{0}\n'{1}'", fileNotFoundMessage, printItem.Name); + //} + } + } + + private void Clear3DGCode() + { + if (gcodeViewWidget?.gCodeRenderer != null) { gcodeViewWidget.gCodeRenderer.Clear3DGCode(); gcodeViewWidget.Invalidate(); @@ -219,49 +270,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow }; string firstProcessingMessage = "Press 'Add' to select an item.".Localize(); - if (printItem != null) - { - firstProcessingMessage = "Loading G-Code...".Localize(); - if (Path.GetExtension(printItem.FileLocation).ToUpper() == ".GCODE") - { - gcodeDisplayWidget.AddChild(CreateGCodeViewWidget(printItem.FileLocation)); - } - else - { - if (File.Exists(printItem.FileLocation)) - { - string gcodePathAndFileName = printItem.GetGCodePathAndFileName(); - bool gcodeFileIsComplete = printItem.IsGCodeFileComplete(gcodePathAndFileName); - - if (printItem.SlicingHadError) - { - firstProcessingMessage = slicingErrorMessage; - } - else - { - firstProcessingMessage = pressGenerateMessage; - } - - if (File.Exists(gcodePathAndFileName) && gcodeFileIsComplete) - { - gcodeDisplayWidget.AddChild(CreateGCodeViewWidget(gcodePathAndFileName)); - } - - // we only hook these up to make sure we can regenerate the gcode when we want - printItem.SlicingOutputMessage += sliceItem_SlicingOutputMessage; - printItem.SlicingDone += sliceItem_Done; - } - else - { - firstProcessingMessage = string.Format("{0}\n'{1}'", fileNotFoundMessage, printItem.Name); - } - } - } - else - { - generateGCodeButton.Visible = false; - } - SetProcessingMessage(firstProcessingMessage); centerPartPreviewAndControls.AddChild(gcodeDisplayWidget); @@ -285,7 +293,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow meshViewerWidget.AllowBedRenderingWhenEmpty = true; gcodeDisplayWidget.AddChild(meshViewerWidget); meshViewerWidget.Visible = false; - meshViewerWidget.TrackballTumbleWidget.DrawGlContent += new EventHandler(TrackballTumbleWidget_DrawGlContent); + meshViewerWidget.TrackballTumbleWidget.DrawGlContent += TrackballTumbleWidget_DrawGlContent; viewControls2D = new ViewControls2D(); AddChild(viewControls2D); @@ -1048,16 +1056,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow CloseIfNotNull(selectLayerSlider); selectLayerSlider = new SolidSlider(new Vector2(), sliderWidth, 0, gcodeViewWidget.LoadedGCode.NumChangesInZ - 1, Orientation.Vertical); - selectLayerSlider.ValueChanged += new EventHandler(selectLayerSlider_ValueChanged); - gcodeViewWidget.ActiveLayerChanged += new EventHandler(gcodeViewWidget_ActiveLayerChanged); + selectLayerSlider.ValueChanged += selectLayerSlider_ValueChanged; + gcodeViewWidget.ActiveLayerChanged += gcodeViewWidget_ActiveLayerChanged; AddChild(selectLayerSlider); CloseIfNotNull(layerRenderRatioSlider); layerRenderRatioSlider = new DoubleSolidSlider(new Vector2(), sliderWidth); layerRenderRatioSlider.FirstValue = 0; - layerRenderRatioSlider.FirstValueChanged += new EventHandler(layerStartRenderRatioSlider_ValueChanged); + layerRenderRatioSlider.FirstValueChanged += layerStartRenderRatioSlider_ValueChanged; layerRenderRatioSlider.SecondValue = 1; - layerRenderRatioSlider.SecondValueChanged += new EventHandler(layerEndRenderRatioSlider_ValueChanged); + layerRenderRatioSlider.SecondValueChanged += layerEndRenderRatioSlider_ValueChanged; AddChild(layerRenderRatioSlider); SetSliderSizes(); @@ -1066,7 +1074,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow gcodeViewWidget.ActiveLayerIndex = gcodeViewWidget.ActiveLayerIndex + 1; gcodeViewWidget.ActiveLayerIndex = gcodeViewWidget.ActiveLayerIndex - 1; - BoundsChanged += new EventHandler(PartPreviewGCode_BoundsChanged); + BoundsChanged += PartPreviewGCode_BoundsChanged; meshViewerWidget.partProcessingInfo.Visible = false; } @@ -1184,7 +1192,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private void DoGenerateButton_Click(object state) { - if (PrinterConnectionAndCommunication.Instance.ActivePrinter != null) + if (ActiveSliceSettings.Instance.PrinterSelected) { if (ActiveSliceSettings.Instance.IsValid() && printItem != null) { @@ -1220,7 +1228,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow printItem.SlicingOutputMessage -= sliceItem_SlicingOutputMessage; printItem.SlicingDone -= sliceItem_Done; - UiThread.RunOnIdle(CreateAndAddChildren); + UiThread.RunOnIdle(() => LoadItem(printItem)); + startedSliceFromGenerateButton = false; } } @@ -1245,10 +1254,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow editCurrentLayerIndex = new NumberEdit(1, pixelWidth: 40); editCurrentLayerIndex.VAnchor = VAnchor.ParentCenter; editCurrentLayerIndex.Margin = new BorderDouble(5, 0); - editCurrentLayerIndex.EditComplete += new EventHandler(editCurrentLayerIndex_EditComplete); + editCurrentLayerIndex.EditComplete += editCurrentLayerIndex_EditComplete; editCurrentLayerIndex.Name = "Current GCode Layer Edit"; this.AddChild(editCurrentLayerIndex); - gcodeViewWidget.ActiveLayerChanged += new EventHandler(gcodeViewWidget_ActiveLayerChanged); + gcodeViewWidget.ActiveLayerChanged += gcodeViewWidget_ActiveLayerChanged; setLayerButton = textImageButtonFactory.Generate("Go".Localize()); setLayerButton.VAnchor = Agg.UI.VAnchor.ParentCenter; diff --git a/PrinterCommunication/PrinterConnectionAndCommunication.cs b/PrinterCommunication/PrinterConnectionAndCommunication.cs index 6944a86de..fa77b5701 100644 --- a/PrinterCommunication/PrinterConnectionAndCommunication.cs +++ b/PrinterCommunication/PrinterConnectionAndCommunication.cs @@ -378,21 +378,16 @@ namespace MatterHackers.MatterControl.PrinterCommunication } set { - if (!PrinterIsPrinting) + if (!PrinterIsPrinting + && !PrinterIsPaused + && this.activePrintItem != value) { - if (this.activePrintItem != value) + this.activePrintItem = value; + if (CommunicationState == CommunicationStates.FinishedPrint) { - this.activePrintItem = value; - if (CommunicationState == CommunicationStates.FinishedPrint) - { - CommunicationState = CommunicationStates.Connected; - } - OnActivePrintItemChanged(null); + CommunicationState = CommunicationStates.Connected; } - } - else - { - throw new Exception("Cannot change active print while printing"); + OnActivePrintItemChanged(null); } } } diff --git a/Queue/OptionsMenu/ExportToFolderProcess.cs b/Queue/OptionsMenu/ExportToFolderProcess.cs index d468c5b6e..f60aa70a8 100644 --- a/Queue/OptionsMenu/ExportToFolderProcess.cs +++ b/Queue/OptionsMenu/ExportToFolderProcess.cs @@ -28,6 +28,7 @@ either expressed or implied, of the FreeBSD Project. */ using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.GCodeVisualizer; using MatterHackers.MatterControl.ConfigurationPage.PrintLeveling; using MatterHackers.MatterControl.DataStorage; diff --git a/Queue/OptionsMenu/PartsSheetCreator.cs b/Queue/OptionsMenu/PartsSheetCreator.cs index 30c34e29a..32495e376 100644 --- a/Queue/OptionsMenu/PartsSheetCreator.cs +++ b/Queue/OptionsMenu/PartsSheetCreator.cs @@ -33,6 +33,7 @@ using MatterHackers.Agg.Image; using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.UI; using MatterHackers.Agg.VertexSource; +using MatterHackers.DataConverters3D; using MatterHackers.MatterControl.DataStorage; using MatterHackers.PolygonMesh; using MatterHackers.PolygonMesh.Processors; @@ -194,12 +195,7 @@ namespace MatterHackers.MatterControl // first create images for all the parts foreach (FileNameAndPresentationName queuePartFileName in queuPartFilesToAdd) { - List loadedMeshGroups = null; - if (File.Exists(queuePartFileName.fileName)) - { - loadedMeshGroups = MeshFileIo.Load(queuePartFileName.fileName); - } - + List loadedMeshGroups = Object3D.Load(queuePartFileName.fileName)?.ToMeshGroupList(); if (loadedMeshGroups != null) { bool firstMeshGroup = true; @@ -216,6 +212,7 @@ namespace MatterHackers.MatterControl aabb = AxisAlignedBoundingBox.Union(aabb, meshGroup.GetAxisAlignedBoundingBox()); } } + RectangleDouble bounds2D = new RectangleDouble(aabb.minXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.x, aabb.maxXYZ.y); double widthInMM = bounds2D.Width + PartMarginMM * 2; double textSpaceMM = 5; diff --git a/Queue/QueueData.cs b/Queue/QueueData.cs index 5379793e6..ac70be7a6 100644 --- a/Queue/QueueData.cs +++ b/Queue/QueueData.cs @@ -30,6 +30,7 @@ either expressed or implied, of the FreeBSD Project. using MatterHackers.Agg; using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.PrinterCommunication; @@ -43,27 +44,13 @@ using System.Linq; namespace MatterHackers.MatterControl.PrintQueue { - public class IndexArgs : EventArgs + public class ItemChangedArgs : EventArgs { - internal int index; + public int Index { get; private set; } - public int Index { get { return index; } } - - internal IndexArgs(int index) + internal ItemChangedArgs(int index) { - this.index = index; - } - } - - public class SwapIndexArgs : EventArgs - { - internal int indexA; - internal int indexB; - - internal SwapIndexArgs(int indexA, int indexB) - { - this.indexA = indexA; - this.indexB = indexB; + this.Index = index; } } @@ -112,13 +99,12 @@ namespace MatterHackers.MatterControl.PrintQueue selectedIndices.Clear(); selectedIndices.Add(value); OnSelectedIndexChanged(null); - } } } + } public RootedObjectEventHandler ItemAdded = new RootedObjectEventHandler(); public RootedObjectEventHandler ItemRemoved = new RootedObjectEventHandler(); - public RootedObjectEventHandler OrderChanged = new RootedObjectEventHandler(); public RootedObjectEventHandler SelectedIndexChanged = new RootedObjectEventHandler(); private static QueueData instance; @@ -182,50 +168,6 @@ namespace MatterHackers.MatterControl.PrintQueue } } - public void SwapItemsOnIdle(int indexA, int indexB) - { - UiThread.RunOnIdle(SwapItems, new SwapIndexArgs(indexA, indexB)); - } - - private void SwapItems(object state) - { - int indexA = ((SwapIndexArgs)state).indexA; - int indexB = ((SwapIndexArgs)state).indexB; - - if (indexA >= 0 && indexA < ItemCount - && indexB >= 0 && indexB < ItemCount - && indexA != indexB) - { - PrintItemWrapper hold = PrintItems[indexA]; - PrintItems[indexA] = PrintItems[indexB]; - PrintItems[indexB] = hold; - - OnOrderChanged(null); - OnSelectedIndexChanged(null); - - SaveDefaultQueue(); - } - } - - public void OnOrderChanged(EventArgs e) - { - OrderChanged.CallEvents(this, e); - } - - public void RemoveIndexOnIdle(int index) - { - UiThread.RunOnIdle(RemoveIndex, new IndexArgs(index)); - } - - private void RemoveIndex(object state) - { - IndexArgs removeArgs = state as IndexArgs; - if (removeArgs != null) - { - RemoveAt(removeArgs.index); - } - } - public void RemoveAt(int index) { if (index >= 0 && index < ItemCount) @@ -236,7 +178,7 @@ namespace MatterHackers.MatterControl.PrintQueue { PrintItems.RemoveAt(index); - OnItemRemoved(new IndexArgs(index)); + OnItemRemoved(new ItemChangedArgs(index)); OnSelectedIndexChanged(null); SaveDefaultQueue(); @@ -363,7 +305,7 @@ namespace MatterHackers.MatterControl.PrintQueue for (int i = 0; i < ItemCount; i++) { var printItem = GetPrintItemWrapper(i).PrintItem; - if (includeProtectedItems + if (includeProtectedItems || !printItem.Protected) { listToReturn.Add(printItem); @@ -447,14 +389,15 @@ namespace MatterHackers.MatterControl.PrintQueue } - private void DoAddItem(PrintItemWrapper item, int indexToInsert) + private void DoAddItem(PrintItemWrapper item, int insertAt) { - if (indexToInsert == -1) + if (insertAt == -1) { - indexToInsert = PrintItems.Count; + insertAt = PrintItems.Count; } - PrintItems.Insert(indexToInsert, item); - OnItemAdded(new IndexArgs(indexToInsert)); + + PrintItems.Insert(insertAt, item); + OnItemAdded(new ItemChangedArgs(insertAt)); OnSelectedIndexChanged(null); SaveDefaultQueue(); } @@ -543,7 +486,7 @@ namespace MatterHackers.MatterControl.PrintQueue foreach (var index in sortedByValue) { RemoveAt(index); - } + } selectedIndices.Clear(); OnSelectedIndexChanged(null); @@ -562,6 +505,11 @@ namespace MatterHackers.MatterControl.PrintQueue } } + public void ToggleSelect(PrintItemWrapper printItem) + { + ToggleSelect(GetIndex(printItem)); + } + public void MakeSingleSelection() { if (ItemCount > 0 diff --git a/Queue/QueueDataView.cs b/Queue/QueueDataView.cs index 9fd9ce2ae..ea4399de0 100644 --- a/Queue/QueueDataView.cs +++ b/Queue/QueueDataView.cs @@ -1,5 +1,5 @@ /* -Copyright (c) 2014, Kevin Pope +Copyright (c) 2016, Kevin Pope, John Lewin All rights reserved. Redistribution and use in source and binary forms, with or without @@ -44,6 +44,8 @@ namespace MatterHackers.MatterControl.PrintQueue { private EventHandler unregisterEvents; + private bool mouseDownWithinQueueItemContainer = false; + // make this private so it can only be built from the Instance private void SetDisplayAttributes() { @@ -69,7 +71,7 @@ namespace MatterHackers.MatterControl.PrintQueue { QueueData.Instance.MakeSingleSelection(); } - SelectedIndexChanged(null, null); + SelectedIndexChanged(); } } } @@ -102,14 +104,12 @@ namespace MatterHackers.MatterControl.PrintQueue return null; } - public delegate void SelectedValueChangedEventHandler(object sender, EventArgs e); + internal FlowLayoutWidget topToBottomItemList; public delegate void HoverValueChangedEventHandler(object sender, EventArgs e); public event HoverValueChangedEventHandler HoverValueChanged; - protected FlowLayoutWidget topToBottomItemList; - private RGBA_Bytes hoverColor = new RGBA_Bytes(204, 204, 204, 255); //RGBA_Bytes hoverColor = new RGBA_Bytes(0, 140, 158, 255); @@ -147,19 +147,16 @@ namespace MatterHackers.MatterControl.PrintQueue for (int i = 0; i < QueueData.Instance.ItemCount; i++) { - PrintItemWrapper item = QueueData.Instance.GetPrintItemWrapper(i); - QueueRowItem queueItem = new QueueRowItem(item, this); - AddChild(queueItem); + topToBottomItemList.AddChild(new WrappedQueueRowItem(this, QueueData.Instance.GetPrintItemWrapper(i))); } - QueueData.Instance.SelectedIndexChanged.RegisterEvent(SelectedIndexChanged, ref unregisterEvents); + QueueData.Instance.SelectedIndexChanged.RegisterEvent((s,e) => SelectedIndexChanged(), ref unregisterEvents); QueueData.Instance.ItemAdded.RegisterEvent(ItemAddedToQueue, ref unregisterEvents); QueueData.Instance.ItemRemoved.RegisterEvent(ItemRemovedFromQueue, ref unregisterEvents); - QueueData.Instance.OrderChanged.RegisterEvent(QueueOrderChanged, ref unregisterEvents); PrinterConnectionAndCommunication.Instance.ActivePrintItemChanged.RegisterEvent(PrintItemChange, ref unregisterEvents); - SelectedIndexChanged(null, null); + SelectedIndexChanged(); } private void PrintItemChange(object sender, EventArgs e) @@ -167,7 +164,7 @@ namespace MatterHackers.MatterControl.PrintQueue QueueData.Instance.SelectedPrintItem = PrinterConnectionAndCommunication.Instance.ActivePrintItem; } - private void SelectedIndexChanged(object sender, EventArgs e) + private void SelectedIndexChanged() { if (this.editMode == false) { @@ -181,12 +178,11 @@ namespace MatterHackers.MatterControl.PrintQueue if (QueueData.Instance.SelectedIndexes.Contains(index)) { - queueRowItem.isSelectedItem = true; queueRowItem.selectionCheckBox.Checked = true; } else { - queueRowItem.isSelectedItem = false; + // Don't test for .Checked as the property already performs validation queueRowItem.selectionCheckBox.Checked = false; } } @@ -194,95 +190,47 @@ namespace MatterHackers.MatterControl.PrintQueue // Skip this processing while in EditMode if (this.editMode) return; - for (int index = 0; index < topToBottomItemList.Children.Count; index++) - { - GuiWidget child = topToBottomItemList.Children[index]; - var queueRowItem = (QueueRowItem)child.Children[0]; - - if (index == QueueData.Instance.SelectedIndex) - { - if (!PrinterConnectionAndCommunication.Instance.PrinterIsPrinting && !PrinterConnectionAndCommunication.Instance.PrinterIsPaused) - { - queueRowItem.isActivePrint = true; - PrinterConnectionAndCommunication.Instance.ActivePrintItem = queueRowItem.PrintItemWrapper; - } - else if (queueRowItem.PrintItemWrapper == PrinterConnectionAndCommunication.Instance.ActivePrintItem) - { - // the selection must be the active print item - queueRowItem.isActivePrint = true; - } - } - else - { - // Don't test for .Checked as the property already performs validation - queueRowItem.selectionCheckBox.Checked = false; - - if (queueRowItem.isSelectedItem) - { - queueRowItem.isSelectedItem = false; - } - - if (!PrinterConnectionAndCommunication.Instance.PrinterIsPrinting && !PrinterConnectionAndCommunication.Instance.PrinterIsPaused) - { - if (queueRowItem.isActivePrint) - { - queueRowItem.isActivePrint = false; - } - } - } - } - - if (QueueData.Instance.ItemCount == 0) - { - PrinterConnectionAndCommunication.Instance.ActivePrintItem = null; - } + PrinterConnectionAndCommunication.Instance.ActivePrintItem = QueueData.Instance.SelectedPrintItem; } private void ItemAddedToQueue(object sender, EventArgs e) { - IndexArgs addedIndexArgs = e as IndexArgs; + var addedIndexArgs = e as ItemChangedArgs; PrintItemWrapper item = QueueData.Instance.GetPrintItemWrapper(addedIndexArgs.Index); - QueueRowItem queueItem = new QueueRowItem(item, this); - AddChild(queueItem, addedIndexArgs.Index); + topToBottomItemList.AddChild(new WrappedQueueRowItem(this, item), addedIndexArgs.Index); } private void ItemRemovedFromQueue(object sender, EventArgs e) { - IndexArgs removeIndexArgs = e as IndexArgs; + var removeIndexArgs = e as ItemChangedArgs; topToBottomItemList.RemoveChild(removeIndexArgs.Index); } - private void QueueOrderChanged(object sender, EventArgs e) - { - throw new NotImplementedException(); - } - public override void OnClosed(ClosedEventArgs e) { - if (unregisterEvents != null) - { - unregisterEvents(this, null); - } + unregisterEvents?.Invoke(this, null); base.OnClosed(e); } - public override void AddChild(GuiWidget childToAdd, int indexInChildrenList = -1) + public override void OnMouseDown(MouseEventArgs mouseEvent) { - FlowLayoutWidget itemHolder = new FlowLayoutWidget(); - itemHolder.Name = "PrintQueueControl itemHolder"; - itemHolder.Margin = new BorderDouble(0, 0, 0, 0); - itemHolder.HAnchor = HAnchor.ParentLeftRight; - itemHolder.AddChild(childToAdd); - itemHolder.VAnchor = VAnchor.FitToChildren; - topToBottomItemList.AddChild(itemHolder, indexInChildrenList); + var topToBottomItemListBounds = topToBottomItemList.LocalBounds; + mouseDownWithinQueueItemContainer = topToBottomItemList.LocalBounds.Contains(mouseEvent.Position); - AddItemHandlers(itemHolder); + base.OnMouseDown(mouseEvent); } - private void AddItemHandlers(GuiWidget itemHolder) + public override void OnMouseUp(MouseEventArgs mouseEvent) { - itemHolder.MouseDownInBounds += itemHolder_MouseDownInBounds; - itemHolder.ParentChanged += new EventHandler(itemHolder_ParentChanged); + mouseDownWithinQueueItemContainer = false; + this.SuppressScroll = false; + base.OnMouseUp(mouseEvent); + } + + public override void OnMouseMove(MouseEventArgs mouseEvent) + { + this.SuppressScroll = mouseDownWithinQueueItemContainer && !PositionWithinLocalBounds(mouseEvent.X, 20); + base.OnMouseMove(mouseEvent); } private bool settingLocalBounds = false; @@ -316,12 +264,7 @@ namespace MatterHackers.MatterControl.PrintQueue } } - private void itemHolder_ParentChanged(object sender, EventArgs e) - { - FlowLayoutWidget itemHolder = (FlowLayoutWidget)sender; - itemHolder.MouseDownInBounds -= itemHolder_MouseDownInBounds; - itemHolder.ParentChanged -= new EventHandler(itemHolder_ParentChanged); - } + public QueueRowItem DragSourceRowItem { get; internal set; } private void itemHolder_MouseDownInBounds(object sender, MouseEventArgs mouseEvent) { diff --git a/Queue/QueueDataWidget.cs b/Queue/QueueDataWidget.cs index 6bc951c5f..ca6ee1eb0 100644 --- a/Queue/QueueDataWidget.cs +++ b/Queue/QueueDataWidget.cs @@ -44,6 +44,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; using MatterHackers.Agg.PlatformAbstract; +using Newtonsoft.Json; +using MatterHackers.PolygonMesh; +using MatterHackers.Agg.VertexSource; +using MatterHackers.DataConverters3D; +using MatterHackers.MatterControl.PartPreviewWindow; +using System.Threading.Tasks; namespace MatterHackers.MatterControl.PrintQueue { @@ -189,7 +195,11 @@ namespace MatterHackers.MatterControl.PrintQueue createButton.Margin = new BorderDouble(0, 0, 3, 0); createButton.Click += (sender, e) => { - OpenPluginChooserWindow(); + // Clear the queue selection + QueueData.Instance.SelectedIndex = -1; + + // Clear the scene and switch to editing view + view3DWidget.ClearBedAndLoadPrintItemWrapper(null, true); }; } @@ -378,8 +388,7 @@ namespace MatterHackers.MatterControl.PrintQueue } else if (extension == ".ZIP") { - ProjectFileHandler project = new ProjectFileHandler(null); - List partFiles = project.ImportFromProjectArchive(fileToAdd); + List partFiles = ProjectFileHandler.ImportFromProjectArchive(fileToAdd); if (partFiles != null) { foreach (PrintItem part in partFiles) @@ -446,8 +455,7 @@ namespace MatterHackers.MatterControl.PrintQueue string extension = Path.GetExtension(fileNameToLoad).ToUpper(); if (extension == ".ZIP") { - ProjectFileHandler project = new ProjectFileHandler(null); - List partFiles = project.ImportFromProjectArchive(fileNameToLoad); + List partFiles = ProjectFileHandler.ImportFromProjectArchive(fileNameToLoad); if (partFiles != null) { foreach (PrintItem part in partFiles) @@ -477,7 +485,7 @@ namespace MatterHackers.MatterControl.PrintQueue QueueData.Instance.AddItem(new PrintItemWrapper(partInfo.PrintItem), partInfo.InsertAfterIndex, QueueData.ValidateSizeOn32BitSystems.Skip); } - void DoAddToSpecificLibrary(SaveAsWindow.SaveAsReturnInfo returnInfo) + void DoAddToSpecificLibrary(SaveAsWindow.SaveAsReturnInfo returnInfo, Action action) { if (returnInfo != null) { @@ -489,18 +497,102 @@ namespace MatterHackers.MatterControl.PrintQueue var queueItem = queueDataView.GetQueueRowItem(queueItemIndex); if (queueItem != null) { - if (File.Exists(queueItem.PrintItemWrapper.FileLocation)) - { - PrintItemWrapper printItemWrapper = new PrintItemWrapper(new PrintItem(queueItem.PrintItemWrapper.PrintItem.Name, queueItem.PrintItemWrapper.FileLocation), returnInfo.destinationLibraryProvider.GetProviderLocator()); - libraryToSaveTo.AddItem(printItemWrapper); - } + if (File.Exists(queueItem.PrintItemWrapper.FileLocation)) + { + PrintItemWrapper printItemWrapper = new PrintItemWrapper(new PrintItem(queueItem.PrintItemWrapper.PrintItem.Name, queueItem.PrintItemWrapper.FileLocation), returnInfo.destinationLibraryProvider.GetProviderLocator()); + libraryToSaveTo.AddItem(printItemWrapper); } } + } libraryToSaveTo.Dispose(); } } } + private View3DWidget view3DWidget; + + public override void OnMouseDown(MouseEventArgs mouseEvent) + { + view3DWidget = MatterControlApplication.Instance.ActiveView3DWidget; + if (view3DWidget == null) + { + base.OnMouseDown(mouseEvent); + return; + } + + var screenSpaceMousePosition = this.TransformToScreenSpace(mouseEvent.Position); + var topToBottomItemListBounds = queueDataView.topToBottomItemList.TransformToScreenSpace(queueDataView.topToBottomItemList.LocalBounds); + + bool mouseInQueueItemList = topToBottomItemListBounds.Contains(screenSpaceMousePosition); + + // Clear or assign a drag source + view3DWidget.DragDropSource = (!mouseInQueueItemList) ? null : new Object3D + { + ItemType = Object3DTypes.Model, + Mesh = PlatonicSolids.CreateCube(10, 10, 10) + }; + + base.OnMouseDown(mouseEvent); + } + + public override void OnMouseMove(MouseEventArgs mouseArgs) + { + if (!this.HasBeenClosed && + view3DWidget?.DragDropSource != null && + queueDataView.DragSourceRowItem != null) + { + var screenSpaceMousePosition = this.TransformToScreenSpace(mouseArgs.Position); + + if(!File.Exists(queueDataView.DragSourceRowItem.PrintItemWrapper.FileLocation)) + { + view3DWidget.DragDropSource = null; + queueDataView.DragSourceRowItem = null; + return; + } + + if(view3DWidget.AltDragOver(screenSpaceMousePosition)) + { + view3DWidget.DragDropSource.MeshPath = queueDataView.DragSourceRowItem.PrintItemWrapper.FileLocation; + + base.OnMouseMove(mouseArgs); + + view3DWidget.LoadDragSource(); + } + } + + base.OnMouseMove(mouseArgs); + } + + public override void OnMouseUp(MouseEventArgs mouseArgs) + { + if (view3DWidget?.DragDropSource != null && view3DWidget.Scene.Children.Contains(view3DWidget.DragDropSource)) + { + // Mouse and widget positions + var screenSpaceMousePosition = this.TransformToScreenSpace(mouseArgs.Position); + var meshViewerPosition = this.view3DWidget.meshViewerWidget.TransformToScreenSpace(view3DWidget.meshViewerWidget.LocalBounds); + + // If the mouse is not within the meshViewer, remove the inserted drag item + if (!meshViewerPosition.Contains(screenSpaceMousePosition)) + { + view3DWidget.Scene.ModifyChildren(children => children.Remove(view3DWidget.DragDropSource)); + view3DWidget.Scene.ClearSelection(); + } + else + { + // Create and push the undo operation + view3DWidget.AddUndoOperation( + new InsertCommand(view3DWidget, view3DWidget.DragDropSource)); + } + } + + if (view3DWidget != null) + { + view3DWidget.DragDropSource = null; + } + + base.OnMouseUp(mouseArgs); + } + private void addToLibraryButton_Click(object sender, EventArgs mouseEvent) { SaveAsWindow saveAsWindow = new SaveAsWindow(DoAddToSpecificLibrary, null, false, false); @@ -544,10 +636,10 @@ namespace MatterHackers.MatterControl.PrintQueue QueueRowItem libraryItem = queueDataView.GetQueueRowItem(QueueData.Instance.SelectedIndex); if (libraryItem != null) { - OpenExportWindow(libraryItem.PrintItemWrapper); - } + OpenExportWindow(libraryItem.PrintItemWrapper); } } + } private void exportQueueButton_Click(object sender, EventArgs mouseEvent) { @@ -632,7 +724,7 @@ namespace MatterHackers.MatterControl.PrintQueue private void removeButton_Click(object sender, EventArgs mouseEvent) { QueueData.Instance.RemoveSelected(); - } + } private void sendButton_Click(object sender, EventArgs mouseEvent) { @@ -709,21 +801,21 @@ namespace MatterHackers.MatterControl.PrintQueue int selectedCount = QueueData.Instance.SelectedCount; // Disable menu items which are singleSelection only - foreach (MenuItem menuItem in moreMenu.MenuItems) + foreach(MenuItem menuItem in moreMenu.MenuItems) { // TODO: Ideally this would set .Enabled but at the moment, disabled controls don't have enough // functionality to convey the disabled aspect or suppress click events if (selectedCount == 1) { menuItem.Enabled = !multiSelectionMenuItems.Contains(menuItem.Text); - } + } else { menuItem.Enabled = !singleSelectionMenuItems.Contains(menuItem.Text); } } - for (int buttonIndex = 0; buttonIndex < itemOperationButtons.Children.Count; buttonIndex++) + for(int buttonIndex=0; buttonIndex 0; var child = itemOperationButtons.Children[buttonIndex]; diff --git a/Queue/QueueRowItem.cs b/Queue/QueueRowItem.cs index b08ad1449..2362bc7b1 100644 --- a/Queue/QueueRowItem.cs +++ b/Queue/QueueRowItem.cs @@ -36,16 +36,33 @@ using MatterHackers.MatterControl.PrinterCommunication; using MatterHackers.VectorMath; using System; using System.Globalization; +using System.Linq; namespace MatterHackers.MatterControl.PrintQueue { public class QueueRowItem : GuiWidget { - public bool isActivePrint = false; + public bool IsActivePrint + { + get + { + return PrinterConnectionAndCommunication.Instance.ActivePrintItem == PrintItemWrapper; + } + } - public bool isHoverItem = false; + private bool isHoverItem = false; - public bool isSelectedItem = false; + public bool IsSelectedItem + { + get + { + if (QueueData.Instance.SelectedIndexes.Contains(QueueData.Instance.GetIndex(PrintItemWrapper))) + { + return true; + } + return false; + } + } public CheckBox selectionCheckBox; @@ -296,7 +313,7 @@ namespace MatterHackers.MatterControl.PrintQueue RectangleDouble Bounds = LocalBounds; RoundedRect rectBorder = new RoundedRect(Bounds, 0); - if (this.isActivePrint && !this.queueDataView.EditMode) + if (this.IsActivePrint && !this.queueDataView.EditMode) { this.BackgroundColor = ActiveTheme.Instance.SecondaryAccentColor; SetTextColors(RGBA_Bytes.White); @@ -306,7 +323,7 @@ namespace MatterHackers.MatterControl.PrintQueue //Draw interior border graphics2D.Render(new Stroke(rectBorder, 3), ActiveTheme.Instance.SecondaryAccentColor); } - else if (this.isSelectedItem) + else if (this.IsSelectedItem) { this.BackgroundColor = ActiveTheme.Instance.PrimaryAccentColor; this.partLabel.TextColor = RGBA_Bytes.White; @@ -365,18 +382,6 @@ namespace MatterHackers.MatterControl.PrintQueue } } - public void ThemeChanged(object sender, EventArgs e) - { - if (this.isActivePrint) - { - //Set background and text color to new theme - this.BackgroundColor = ActiveTheme.Instance.PrimaryAccentColor; - this.partLabel.TextColor = RGBA_Bytes.White; - this.partStatus.TextColor = RGBA_Bytes.White; - this.Invalidate(); - } - } - internal void DeletePartFromQueue() { if (PrintItemWrapper.PrintItem.FileLocation == QueueData.SdCardFileName) @@ -384,15 +389,16 @@ namespace MatterHackers.MatterControl.PrintQueue StyledMessageBox.ShowMessageBox(onDeleteFileConfirm, alsoRemoveFromSdCardMessage, alsoRemoveFromSdCardTitle, StyledMessageBox.MessageType.YES_NO); } - int thisIndexInQueue = QueueData.Instance.GetIndex(PrintItemWrapper); - QueueData.Instance.RemoveIndexOnIdle(thisIndexInQueue); + int index = QueueData.Instance.GetIndex(PrintItemWrapper); + UiThread.RunOnIdle(() => QueueData.Instance.RemoveAt(index)); } private static void onConfirmRemove(bool messageBoxResponse) { if (messageBoxResponse) { - QueueData.Instance.RemoveIndexOnIdle(QueueData.Instance.GetIndex(itemToRemove)); + int index = QueueData.Instance.GetIndex(itemToRemove); + UiThread.RunOnIdle(() => QueueData.Instance.RemoveAt(index)); } } diff --git a/Queue/WrappedQueueRowItem.cs b/Queue/WrappedQueueRowItem.cs new file mode 100644 index 000000000..3d4ec7b9b --- /dev/null +++ b/Queue/WrappedQueueRowItem.cs @@ -0,0 +1,109 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg; +using MatterHackers.Agg.UI; +using MatterHackers.Agg.VertexSource; +using MatterHackers.Localizations; +using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.MatterControl.PrinterCommunication; +using MatterHackers.VectorMath; +using System; +using System.Globalization; + +namespace MatterHackers.MatterControl.PrintQueue +{ + public class WrappedQueueRowItem : FlowLayoutWidget + { + private bool mouseDownInBounds = false; + + private QueueDataView queueDataView; + private QueueRowItem queueRowItem; + + public WrappedQueueRowItem(QueueDataView parent, PrintItemWrapper printItem) + { + Name = "PrintQueueControl itemHolder"; + Margin = new BorderDouble(0, 0, 0, 0); + HAnchor = HAnchor.ParentLeftRight; + VAnchor = VAnchor.FitToChildren; + + this.queueDataView = parent; + this.queueRowItem = new QueueRowItem(printItem, parent); + + AddChild(this.queueRowItem); + } + + public override void OnMouseEnterBounds(MouseEventArgs mouseEvent) + { + queueRowItem.IsHoverItem = true; + + base.OnMouseEnterBounds(mouseEvent); + } + + public override void OnMouseLeaveBounds(MouseEventArgs mouseEvent) + { + queueRowItem.IsHoverItem = false; + base.OnMouseLeaveBounds(mouseEvent); + } + + Vector2 mouseDownAt; + public override void OnMouseDown(MouseEventArgs mouseEvent) + { + mouseDownAt = mouseEvent.Position; + mouseDownInBounds = true; + base.OnMouseDown(mouseEvent); + } + + public override void OnMouseMove(MouseEventArgs mouseEvent) + { + var delta = mouseDownAt - mouseEvent.Position; + if (mouseDownInBounds && delta.Length > 50) + { + // Set the QueueRowItem child as the DragSourceRowItem for use in drag/drop + queueDataView.DragSourceRowItem = queueRowItem; + } + + base.OnMouseMove(mouseEvent); + } + + public override void OnMouseUp(MouseEventArgs mouseEvent) + { + // If a valid click event occurs then set the selected index in our parent + if (mouseDownInBounds && + (queueDataView.EditMode || mouseEvent.X > 56) && // Disregard clicks within the thumbnail region (x < 56) + PositionWithinLocalBounds(mouseEvent.X, mouseEvent.Y)) + { + QueueData.Instance.ToggleSelect(queueRowItem.PrintItemWrapper); + } + + mouseDownInBounds = false; + base.OnMouseUp(mouseEvent); + } + } +} \ No newline at end of file diff --git a/SettingsManagement/ApplicationSettings.cs b/SettingsManagement/ApplicationSettings.cs index f5a703bee..78ed06901 100644 --- a/SettingsManagement/ApplicationSettings.cs +++ b/SettingsManagement/ApplicationSettings.cs @@ -20,11 +20,11 @@ namespace MatterHackers.MatterControl public class ApplicationSettings { - public static string LibraryFilterFileExtensions { get { return ".stl,.amf,.gcode"; } } + public static string LibraryFilterFileExtensions { get { return ".stl,.amf,.gcode,.mcx"; } } - public static string OpenPrintableFileParams { get { return "STL, AMF, ZIP, GCODE|*.stl;*.amf;*.zip;*.gcode"; } } + public static string OpenPrintableFileParams { get { return "STL, AMF, ZIP, GCODE, MCX|*.stl;*.amf;*.zip;*.gcode;*.mcx"; } } - public static string OpenDesignFileParams { get { return "STL, AMF, ZIP, GCODE|*.stl;*.amf;*.zip;*.gcode"; } } + public static string OpenDesignFileParams { get { return "STL, AMF, ZIP, GCODE, MCX|*.stl;*.amf;*.zip;*.gcode;*.mcx" ; } } private static ApplicationSettings globalInstance = null; public Dictionary settingsDictionary; diff --git a/SlicerConfiguration/SlicerMapping/EngineMapingBase.cs b/SlicerConfiguration/SlicerMapping/EngineMapingBase.cs index b2c185512..c57989a59 100644 --- a/SlicerConfiguration/SlicerMapping/EngineMapingBase.cs +++ b/SlicerConfiguration/SlicerMapping/EngineMapingBase.cs @@ -88,7 +88,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration }; public SliceEngineMapping(string engineName) - { + { this.Name = engineName; } diff --git a/SlicerConfiguration/SlicerMapping/EngineMappingCura.cs b/SlicerConfiguration/SlicerMapping/EngineMappingCura.cs index f8f4c580d..9f124e553 100644 --- a/SlicerConfiguration/SlicerMapping/EngineMappingCura.cs +++ b/SlicerConfiguration/SlicerMapping/EngineMappingCura.cs @@ -95,6 +95,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration new ScaledSingleNumber("support_material_xy_distance", "supportXYDistance", 1000), new ScaledSingleNumber("support_material_z_distance", "supportZDistance", 1000), + // This needs to be passed to cura (but not matter slice). The actual value is set in "support_material", "supportAngle" but is found in this value. + new VisibleButNotMappedToEngine("support_material_threshold"), + new SupportTypeMapping("support_type", "supportType"), new MappedSetting("slowdown_below_layer_time", "minimalLayerTime"), diff --git a/SlicerConfiguration/SlicingQueue.cs b/SlicerConfiguration/SlicingQueue.cs index a2258c6db..d5439dc82 100644 --- a/SlicerConfiguration/SlicingQueue.cs +++ b/SlicerConfiguration/SlicingQueue.cs @@ -1,6 +1,7 @@ using MatterHackers.Agg; using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.PrintQueue; @@ -203,8 +204,10 @@ namespace MatterHackers.MatterControl.SlicerConfiguration extrudersUsed[0] = true; return new string[] { fileToSlice }; + case ".MCX": case ".AMF": - List meshGroups = MeshFileIo.Load(fileToSlice); + // TODO: Once graph parsing is added to MatterSlice we can remove and avoid this flattening + List meshGroups = new List { Object3D.Load(fileToSlice).Flatten() }; if (meshGroups != null) { List extruderMeshGroups = new List(); @@ -251,7 +254,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration if (doMergeInSlicer) { int meshCount = meshGroup.Meshes.Count; - for (int meshIndex =0; meshIndex< meshCount; meshIndex++) + for (int meshIndex =0; meshIndex< meshCount; meshIndex++) { Mesh mesh = meshGroup.Meshes[meshIndex]; if ((meshIndex % 2) == 0) @@ -318,8 +321,12 @@ namespace MatterHackers.MatterControl.SlicerConfiguration { Directory.CreateDirectory(folderToSaveStlsTo); } - MeshOutputSettings settings = new MeshOutputSettings(); - settings.MaterialIndexsToSave = materialIndexsToSaveInThisSTL; + + MeshOutputSettings settings = new MeshOutputSettings() + { + MaterialIndexsToSave = materialIndexsToSaveInThisSTL + }; + string extruder1StlFileToSlice = Path.Combine(folderToSaveStlsTo, fileName); MeshFileIo.Save(extruderMeshGroup, extruder1StlFileToSlice, settings); return extruder1StlFileToSlice; @@ -340,7 +347,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration bool doMergeInSlicer = false; string mergeRules = ""; doMergeInSlicer = ActiveSliceSettings.Instance.Helpers.ActiveSliceEngineType() == SlicingEngineTypes.MatterSlice; - string[] stlFileLocations = GetStlFileLocations(itemToSlice.FileLocation, doMergeInSlicer, ref mergeRules); + string[] stlFileLocations = GetStlFileLocations(itemToSlice.FileLocation, doMergeInSlicer, ref mergeRules); string fileToSlice = stlFileLocations[0]; // check that the STL file is currently on disk if (File.Exists(fileToSlice)) diff --git a/StaticData/Icons/3D Icons/ImageConverter.png b/StaticData/Icons/3D Icons/ImageConverter.png new file mode 100644 index 000000000..184f517fb Binary files /dev/null and b/StaticData/Icons/3D Icons/ImageConverter.png differ diff --git a/StaticData/Icons/mh-logo.png b/StaticData/Icons/mh-logo.png new file mode 100644 index 000000000..29407ad4b Binary files /dev/null and b/StaticData/Icons/mh-logo.png differ diff --git a/StaticData/PrinterSettings/JumpStart/V1/config.ini b/StaticData/PrinterSettings/JumpStart/V1/config.ini new file mode 100644 index 000000000..426f4da8a --- /dev/null +++ b/StaticData/PrinterSettings/JumpStart/V1/config.ini @@ -0,0 +1,168 @@ +avoid_crossing_perimeters = 1 +bed_shape = rectangular +bed_size = 190,250 +bed_temperature = 0 +bottom_clip_amount = 0 +bottom_solid_layers = 4 +bridge_acceleration = 0 +bridge_fan_speed = 100 +bridge_flow_ratio = 1 +bridge_speed = 40 +brim_width = 3 +build_height = 200 +cancel_gcode = G28 X0\n +center_part_on_bed = 1 +complete_objects = 0 +connect_gcode = M205 X8\nM201 X1000 Y1500 Z100 E3000\nM204 S0 T1800 +cool_extruder_lift = 1 +print_leveling_solution = 3 Point Plane +print_leveling_method = Manual +print_leveling_required_to_print = 1 +manual_probe_paper_width = .1 +cooling = 1 +create_raft = 0 +default_acceleration = 0 +disable_fan_first_layers = 0 +end_gcode = M104 S0 ; turn off temperature\nG1 X10 Y200\nM84 ; disable motors +external_perimeter_speed = 25 +external_perimeters_first = 0 +extra_perimeters = 1 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extruder_count = 1 +extruder_offset = 0x0 +extruder_wipe_temperature = 0 +extruders_share_temperature = 0 +extrusion_axis = E +extrusion_multiplier = 1 +extrusion_width = 0 +fan_always_on = 0 +fan_below_layer_time = 60 +filament_diameter = 1.75 +fill_angle = 45 +fill_density = 30% +fill_pattern = rectilinear +first_layer_acceleration = 0 +first_layer_bed_temperature = 85 +first_layer_extrusion_width = 125% +first_layer_height = 0.3 +first_layer_speed = 15 +first_layer_temperature = 230 +g0 = 0 +gap_fill_speed = 30 +gcode_arcs = 0 +gcode_comments = 1 +gcode_flavor = reprap +gcode_output_type = REPRAP +has_fan = 0 +has_hardware_leveling = 0 +has_heated_bed = 0 +has_power_control = 0 +has_sd_card_reader = 1 +show_reset_connection = 0 +heat_extruder_before_homing = 1 +include_firmware_updater = Simple Arduino +infill_acceleration = 0 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0 +infill_first = 0 +infill_only_where_needed = 1 +infill_overlap_perimeter = 0.2 +infill_speed = 45 +infill_type = TRIANGLES +layer_height = 0.2 +layer_to_pause = +max_fan_speed = 100 +min_extrusion_before_retract = 0.1 +min_fan_speed = 100 +min_print_speed = 15 +min_skirt_length = 5 +notes = +nozzle_diameter = 0.4 +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 1 +pause_gcode = +perimeter_acceleration = 0 +perimeter_extruder = 1 +perimeter_extrusion_width = 0 +external_perimeter_extrusion_width = 0 +perimeter_speed = 35 +perimeters = 2 +post_process = +print_center = 95,125 +raft_air_gap = 0.2 +raft_extruder = 0 +raft_extra_distance_around_part = 3 +raft_fan_speed_percent = 100 +raft_layers = 0 +raft_print_speed = 25 +bed_remove_part_temperature = 0 +randomize_start = 1 +repair_outlines_extensive_stitching = 1 +repair_outlines_keep_open = 1 +resolution = 0 +resume_gcode = +retract_before_travel = 10 +retract_layer_change = 1 +retract_length = 3 +retract_length_tool_change = 10 +retract_lift = 0 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_when_changing_islands = 1 +retract_speed = 50 +skirt_distance = 3 +skirt_height = 1 +skirts = 4 +slowdown_below_layer_time = 20 +small_perimeter_speed = 30 +solid_fill_pattern = rectilinear +solid_infill_below_area = 70 +solid_infill_every_layers = 0 +solid_infill_extrusion_width = 0 +solid_infill_speed = 60 +solid_shell = 0 +spiral_vase = 0 +standby_temperature_delta = -5 +start_gcode = G28 ; home all axes\nG1 Z10 F5000 ; lift nozzle +start_perimeters_at_concave_points = 1 +start_perimeters_at_non_overhang = 1 +support_air_gap = 0.25 +support_material = 0 +support_material_angle = 0 +support_material_percent = 50 +support_material_create_perimeter = 1 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0 +support_material_infill_angle = 45 +support_material_interface_extruder = 1 +support_material_interface_layers = 3 +support_material_interface_spacing = 1 +support_material_pattern = rectilinear +support_material_spacing = 3 +support_material_speed = 40 +support_material_threshold = 45 +support_material_xy_distance = 1.5 +support_material_z_distance = 0.15 +support_material_z_gap_layers = 4 +support_type = LINES +temperature = 210 +thin_walls = 1 +threads = 3 +toolchange_gcode = +top_infill_extrusion_width = 0 +top_solid_infill_speed = 35 +top_solid_layers = 4 +travel_speed = 100 +use_firmware_retraction = 0 +use_relative_e_distances = 0 +vibration_limit = 0 +wipe = 0 +wipe_shield_distance = 0 +wipe_tower_size = 0 +z_can_be_negative = 0 +z_offset = 0.2 diff --git a/StaticData/SliceSettings/Layouts.txt b/StaticData/SliceSettings/Layouts.txt index a70d1e448..e38911efb 100644 --- a/StaticData/SliceSettings/Layouts.txt +++ b/StaticData/SliceSettings/Layouts.txt @@ -39,12 +39,13 @@ Intermediate Support Material support_material support_type + support_material_threshold + support_material_percent + Support Options + support_material_spacing support_material_interface_layers support_material_z_gap_layers support_material_create_internal_support - Support Options - support_material_spacing - support_material_percent Extruders support_material_extruder Filament @@ -164,12 +165,12 @@ Advanced support_material support_type support_material_threshold + support_material_percent support_material_enforce_layers Support Options support_material_pattern support_material_spacing support_material_angle - support_material_percent support_material_infill_angle support_material_interface_layers support_material_interface_spacing diff --git a/StaticData/Translations/Master.txt b/StaticData/Translations/Master.txt index 37edae13b..bcef14442 100644 --- a/StaticData/Translations/Master.txt +++ b/StaticData/Translations/Master.txt @@ -5836,125 +5836,119 @@ Translated:The z offset to apply to improve the first layer adhesion. English:Baby Step Offset Translated:Baby Step Offset -English:Oops! Unable to initialize device. -Translated:Oops! Unable to initialize device. +English:Overhang +Translated:Overhang + +English:OpenSCAD1 +Translated:OpenSCAD1 + +English:TEXT +Translated:TEXT + +English:Text +Translated:Text + +English:Braille +Translated:Braille + +English:Height +Translated:Height + +English:Depth +Translated:Depth + +English:Update +Translated:Update + +English:XOffset +Translated:XOffset + +English:HeightFromFloorToBottomOfLeg +Translated:HeightFromFloorToBottomOfLeg + +English:OuterSize +Translated:OuterSize + +English:InnerSize +Translated:InnerSize + +English:InsideReach +Translated:InsideReach + +English:AngleDegrees +Translated:AngleDegrees + +English:Color +Translated:Color + +English:Rotation Count: +Translated:Rotation Count: + +English:Radius +Translated:Radius + +English:Submit Button +Translated:Submit Button + +English:Enter 12 Digit Redemption Code +Translated:Enter 12 Digit Redemption Code + +English:This is located on the rear of your card +Translated:This is located on the rear of your card + +English:Please wait. Verifying code... +Translated:Please wait. Verifying code... + +English:View Designs +Translated:View Designs + +English:Success! Your code has been redeemed. +Translated:Success! Your code has been redeemed. + +English:Your new designs will appear in the 'Purchased' library folder. +Translated:Your new designs will appear in the 'Purchased' library folder. English:The distance between the top of the raft and the bottom of the model. 0.6 mm is a good starting point for PLA and 0.4 mm is a good starting point for ABS. Lower values give a smoother surface, higher values make the print easier to remove. Translated:The distance between the top of the raft and the bottom of the model. 0.6 mm is a good starting point for PLA and 0.4 mm is a good starting point for ABS. Lower values give a smoother surface, higher values make the print easier to remove. -English:Clear ZOffset -Translated:Clear ZOffset - -English:Printing Window... -Translated:Printing Window... - -English:Only Retract When Crossing Perimeters -Translated:Only Retract When Crossing Perimeters - -English:baby_step_z_offset -Translated:baby_step_z_offset - -English:gcode_arcs -Translated:gcode_arcs - -English:calibration_files -Translated:calibration_files - -English:'External Perimeter Extrusion Width' must be less than or equal to the 'Nozzle Diameter' * 4. -Translated:'External Perimeter Extrusion Width' must be less than or equal to the 'Nozzle Diameter' * 4. - -English:External Perimeter Extrusion Width = {0}\nNozzle Diameter = {1} -Translated:External Perimeter Extrusion Width = {0}\nNozzle Diameter = {1} - -English:Location: 'Settings & Controls' -> 'Settings' -> 'Filament' -> 'Extrusion' -> 'External Perimeter' -Translated:Location: 'Settings & Controls' -> 'Settings' -> 'Filament' -> 'Extrusion' -> 'External Perimeter' - -English:'External Perimeter Extrusion Width' must be greater than 0. -Translated:'External Perimeter Extrusion Width' must be greater than 0. - -English:External Perimeter Extrusion Width = {0} -Translated:External Perimeter Extrusion Width = {0} - English:The starting height (z) of the print head before probing each print level position. Translated:The starting height (z) of the print head before probing each print level position. -English:Probe Start Height -Translated:Probe Start Height - English:Controls the speed of printer moves Translated:Controls the speed of printer moves English:Controls the amount of extrusion Translated:Controls the amount of extrusion -English:feedrate_ratio -Translated:feedrate_ratio +English:Axis movement speeds +Translated:Axis movement speeds -English:extrusion_ratio -Translated:extrusion_ratio +English:Printing Window... +Translated:Printing Window... -English:Choose the material that you are loading. -Translated:Choose the material that you are loading. +English:Clear ZOffset +Translated:Clear ZOffset -English:Trim the end of the filament to ensure a good load. -Translated:Trim the end of the filament to ensure a good load. - -English:Choose the material that you are loading. You are doing some stuff that takes a long description. -Translated:Choose the material that you are loading. You are doing some stuff that takes a long description. - -English:Confirm the material you are unloading. -Translated:Confirm the material you are unloading. - -English:Waiting for extruder to heat to 205, before unloading. -Translated:Waiting for extruder to heat to 205, before unloading. - -English:Unloading filament... -Translated:Unloading filament... - -English:Put filament into extruder and click Continue. -Translated:Put filament into extruder and click Continue. - -English:Loading filament... -Translated:Loading filament... - -English:Waiting for extruder to heat to 205. -Translated:Waiting for extruder to heat to 205. - -English:Click 'Continue' when filament is running cleanly. -Translated:Click 'Continue' when filament is running cleanly. - -English:Heating side 1. -Translated:Heating side 1. - -English:Turn Sandvich over! -Translated:Turn Sandvich over! - -English:Heating side 2. -Translated:Heating side 2. - -English:Done! -Translated:Done! +English:Probe Start Height +Translated:Probe Start Height English:WARNING: In order to perform print recovery, your printer must move down to reach its home position.\nIf your print is too large, part of your printer may collide with it when moving down.\nMake sure it is safe to perform this operation before proceeding. Translated:WARNING: In order to perform print recovery, your printer must move down to reach its home position.\nIf your print is too large, part of your printer may collide with it when moving down.\nMake sure it is safe to perform this operation before proceeding. -English:Print Monitor -Translated:Print Monitor +English:Images +Translated:Images -English:Currently Printing -Translated:Currently Printing +English:Select Image +Translated:Select Image -English:Homing Axis -Translated:Homing Axis +English:Creating Mesh +Translated:Creating Mesh -English:Waiting for Extruder to Heat to -Translated:Waiting for Extruder to Heat to +English:Updating Mesh +Translated:Updating Mesh -English:Waiting for Bed to Heat to -Translated:Waiting for Bed to Heat to - -English:Bed -Translated:Bed +English:Updating Base +Translated:Updating Base English:Axis movement speeds Translated:Axis movement speeds diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index 924e9cb5a..79c9fd73b 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit 924e9cb5a7c98096f580cc140a8b418387bc8b94 +Subproject commit 79c9fd73b83111d7fb7f42699c983e72f03c6bdf diff --git a/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj b/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj index a180ff703..e1700bdec 100644 --- a/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj +++ b/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj @@ -91,6 +91,10 @@ {657dbc6d-c3ea-4398-a3fa-ddb73c14f71b} Agg + + {04667764-dc7b-4b95-aef6-b4e6c87a54e9} + DataConverters3D + {e9102310-0029-4d8f-b1e9-88fba6147d45} GuiAutomation diff --git a/Tests/MatterControl.AutomationTests/PartPreviewTests.cs b/Tests/MatterControl.AutomationTests/PartPreviewTests.cs index 53dc830f9..06024c803 100644 --- a/Tests/MatterControl.AutomationTests/PartPreviewTests.cs +++ b/Tests/MatterControl.AutomationTests/PartPreviewTests.cs @@ -35,25 +35,25 @@ namespace MatterHackers.MatterControl.Tests.Automation View3DWidget view3D = testRunner.GetWidgetByName("View3DWidget", out systemWindow, 3) as View3DWidget; // Click Edit button to make edit controls visible - testRunner.ClickByName("3D View Edit"); testRunner.WaitForName("3D View Copy", 3); - Assert.AreEqual(1, view3D.MeshGroups.Count, "Should have 1 part before copy"); + Assert.AreEqual(1, view3D.Scene.Children.Count, "Should have 1 part before copy"); + testRunner.Select3DPart("Calibration - Box"); - // Click Copy button and count MeshGroups + // Click Copy button and count Scene.Children testRunner.ClickByName("3D View Copy"); - testRunner.Delay(() => view3D.MeshGroups.Count == 2, 3); - Assert.AreEqual(2, view3D.MeshGroups.Count, "Should have 2 parts after copy"); + testRunner.Delay(() => view3D.Scene.Children.Count == 2, 3); + Assert.AreEqual(2, view3D.Scene.Children.Count, "Should have 2 parts after copy"); - // Click Copy button a second time and count MeshGroups + // Click Copy button a second time and count Scene.Children testRunner.ClickByName("3D View Copy"); - testRunner.Delay(() => view3D.MeshGroups.Count == 3, 3); - Assert.AreEqual(3, view3D.MeshGroups.Count, "Should have 3 parts after 2nd copy"); + testRunner.Delay(() => view3D.Scene.Children.Count == 3, 3); + Assert.AreEqual(3, view3D.Scene.Children.Count, "Should have 3 parts after 2nd copy"); return Task.FromResult(0); }; - await MatterControlUtilities.RunTest(testToRun, overrideWidth: 800); + await MatterControlUtilities.RunTest(testToRun, overrideWidth: 800, maxTimeToRun: 60); } [Test, Apartment(ApartmentState.STA)] @@ -63,8 +63,6 @@ namespace MatterHackers.MatterControl.Tests.Automation { testRunner.CloseSignInAndPrinterSelect(); - SystemWindow systemWindow; - //Navigate to Local Library testRunner.ClickByName("Library Tab"); testRunner.NavigateToFolder("Local Library Row Item Collection"); @@ -72,36 +70,33 @@ namespace MatterHackers.MatterControl.Tests.Automation testRunner.ClickByName("Row Item Calibration - Box"); MatterControlUtilities.LibraryEditSelectedItem(testRunner); - //Get View3DWidget and count MeshGroups before Copy button is clicked + //Get View3DWidget and count Scene.Children before Copy button is clicked + SystemWindow systemWindow; GuiWidget partPreview = testRunner.GetWidgetByName("View3DWidget", out systemWindow, 3); View3DWidget view3D = partPreview as View3DWidget; - string copyButtonName = "3D View Copy"; - - int partCountBeforeCopy = view3D.MeshGroups.Count; + int partCountBeforeCopy = view3D.Scene.Children.Count(); Assert.IsTrue(partCountBeforeCopy == 1); for (int i = 0; i <= 4; i++) { - testRunner.ClickByName(copyButtonName); - testRunner.Delay(1); + testRunner.ClickByName("3D View Copy"); + testRunner.Delay(() => view3D.Scene.Children.Count == i+2, 3); + Assert.AreEqual(i + 2, view3D.Scene.Children.Count, $"Should have {i+2} parts after copy"); } //Get MeshGroupCount before Group is clicked - System.Threading.Thread.Sleep(2000); - int partsOnBedBeforeGroup = view3D.MeshGroups.Count; - Assert.IsTrue(partsOnBedBeforeGroup == 6); + Assert.AreEqual(6, view3D.Scene.Children.Count()); + + testRunner.Type("^a"); - //Click Group Button and get MeshGroup count after Group button is clicked testRunner.ClickByName("3D View Group"); - System.Threading.Thread.Sleep(2000); - int partsOnBedAfterGroup = view3D.MeshGroups.Count; - Assert.IsTrue(partsOnBedAfterGroup == 1); + testRunner.Delay(() => view3D.Scene.Children.Count == 1, 3); + Assert.AreEqual(1, view3D.Scene.Children.Count, $"Should have 1 parts after group"); testRunner.ClickByName("3D View Ungroup"); - System.Threading.Thread.Sleep(2000); - int partsOnBedAfterUngroup = view3D.MeshGroups.Count; - Assert.IsTrue(partsOnBedAfterUngroup == 6); + testRunner.Delay(() => view3D.Scene.Children.Count == 6, 3); + Assert.AreEqual(6, view3D.Scene.Children.Count, $"Should have 6 parts after ungroup"); return Task.FromResult(0); }; @@ -125,13 +120,13 @@ namespace MatterHackers.MatterControl.Tests.Automation testRunner.ClickByName("Row Item Calibration - Box"); MatterControlUtilities.LibraryEditSelectedItem(testRunner); - //Get View3DWidget and count MeshGroups before Copy button is clicked + //Get View3DWidget and count Scene.Children before Copy button is clicked GuiWidget partPreview = testRunner.GetWidgetByName("View3DWidget", out systemWindow, 3); View3DWidget view3D = partPreview as View3DWidget; string copyButtonName = "3D View Copy"; - int partCountBeforeCopy = view3D.MeshGroups.Count; + int partCountBeforeCopy = view3D.Scene.Children.Count(); Assert.IsTrue(partCountBeforeCopy == 1); for (int i = 0; i <= 4; i++) @@ -142,13 +137,13 @@ namespace MatterHackers.MatterControl.Tests.Automation //Get MeshGroupCount before Group is clicked System.Threading.Thread.Sleep(2000); - int partsOnBedBeforeRemove = view3D.MeshGroups.Count; + int partsOnBedBeforeRemove = view3D.Scene.Children.Count(); Assert.IsTrue(partsOnBedBeforeRemove == 6); //Check that MeshCount decreases by 1 testRunner.ClickByName("3D View Remove"); System.Threading.Thread.Sleep(2000); - int meshCountAfterRemove = view3D.MeshGroups.Count; + int meshCountAfterRemove = view3D.Scene.Children.Count(); Assert.IsTrue(meshCountAfterRemove == 5); return Task.FromResult(0); @@ -172,34 +167,48 @@ namespace MatterHackers.MatterControl.Tests.Automation testRunner.ClickByName("Row Item Calibration - Box"); MatterControlUtilities.LibraryEditSelectedItem(testRunner); - // Get View3DWidget and count MeshGroups before Copy button is clicked - View3DWidget view3D = testRunner.GetWidgetByName("View3DWidget", out systemWindow, 3) as View3DWidget; + //Get View3DWidget and count Scene.Children before Copy button is clicked + GuiWidget partPreview = testRunner.GetWidgetByName("View3DWidget", out systemWindow, 3); + View3DWidget view3D = partPreview as View3DWidget; + + string copyButtonName = "3D View Copy"; + + //Click Edit button to make edit controls visible + testRunner.Delay(1); + int partCountBeforeCopy = view3D.Scene.Children.Count(); + Assert.IsTrue(partCountBeforeCopy == 1); for (int i = 0; i <= 4; i++) { - testRunner.ClickByName("3D View Copy"); - testRunner.Delay(() => view3D.MeshGroups.Count == i + 2, 2); - Assert.AreEqual(i + 2, view3D.MeshGroups.Count); + testRunner.ClickByName(copyButtonName); + testRunner.Delay(() => view3D.Scene.Children.Count() == i + 2, 2); + Assert.AreEqual(view3D.Scene.Children.Count(), i + 2); } testRunner.Delay(.2); for (int x = 0; x <= 4; x++) { - int meshCountBeforeUndo = view3D.MeshGroups.Count; + int meshCountBeforeUndo = view3D.Scene.Children.Count(); testRunner.ClickByName("3D View Undo"); - testRunner.Delay(() => view3D.MeshGroups.Count == meshCountBeforeUndo - 1, 2); - Assert.AreEqual(meshCountBeforeUndo - 1, view3D.MeshGroups.Count); + + testRunner.Delay( + () => view3D.Scene.Children.Count() == meshCountBeforeUndo-1, + 2); + Assert.AreEqual(view3D.Scene.Children.Count(), meshCountBeforeUndo - 1); } testRunner.Delay(.2); for (int z = 0; z <= 4; z++) { - int meshCountBeforeRedo = view3D.MeshGroups.Count; + int meshCountBeforeRedo = view3D.Scene.Children.Count(); testRunner.ClickByName("3D View Redo"); - testRunner.Delay(() => view3D.MeshGroups.Count == meshCountBeforeRedo + 1, 2); - Assert.AreEqual(meshCountBeforeRedo + 1, view3D.MeshGroups.Count); + + testRunner.Delay( + () => meshCountBeforeRedo + 1 == view3D.Scene.Children.Count(), + 2); + Assert.AreEqual(meshCountBeforeRedo + 1, view3D.Scene.Children.Count()); } return Task.FromResult(0); @@ -229,7 +238,7 @@ namespace MatterHackers.MatterControl.Tests.Automation // Click Edit button to make edit controls visible testRunner.WaitForName("3D View Copy", 3); testRunner.Delay(1); // wait for window to finish opening - Assert.AreEqual(1, view3D.MeshGroups.Count, "Should have 1 part before copy"); + Assert.AreEqual(1, view3D.Scene.Children.Count, "Should have 1 part before copy"); for (int i = 0; i <= 4; i++) { @@ -237,19 +246,19 @@ namespace MatterHackers.MatterControl.Tests.Automation testRunner.Delay(.2); } - Assert.AreEqual(6, view3D.MeshGroups.Count, "Should have 6 parts after batch copy"); + Assert.AreEqual(6, view3D.Scene.Children.Count, "Should have 6 parts after batch copy"); testRunner.ClickByName("3D View Remove", 1); - testRunner.Delay(() => view3D.MeshGroups.Count == 5, 3); - Assert.AreEqual(5, view3D.MeshGroups.Count, "Should have 5 parts after Remove"); + testRunner.Delay(() => view3D.Scene.Children.Count == 5, 3); + Assert.AreEqual(5, view3D.Scene.Children.Count, "Should have 5 parts after Remove"); testRunner.ClickByName("3D View Undo"); - testRunner.Delay(() => view3D.MeshGroups.Count == 6, 3); - Assert.AreEqual(6, view3D.MeshGroups.Count, "Should have 6 parts after Undo"); + testRunner.Delay(() => view3D.Scene.Children.Count == 6, 3); + Assert.AreEqual(6, view3D.Scene.Children.Count, "Should have 6 parts after Undo"); testRunner.ClickByName("3D View Redo"); - testRunner.Delay(() => view3D.MeshGroups.Count == 5, 3); - Assert.AreEqual(5, view3D.MeshGroups.Count, "Should have 5 parts after Redo"); + testRunner.Delay(() => view3D.Scene.Children.Count == 5, 3); + Assert.AreEqual(5, view3D.Scene.Children.Count, "Should have 5 parts after Redo"); view3D.CloseOnIdle(); testRunner.Delay(.1); diff --git a/Tests/MatterControl.AutomationTests/PrintQueueTests.cs b/Tests/MatterControl.AutomationTests/PrintQueueTests.cs index 1ce52ee82..321f64334 100644 --- a/Tests/MatterControl.AutomationTests/PrintQueueTests.cs +++ b/Tests/MatterControl.AutomationTests/PrintQueueTests.cs @@ -34,8 +34,10 @@ using System.Threading.Tasks; using MatterHackers.Agg.UI; using MatterHackers.Agg.UI.Tests; using MatterHackers.GuiAutomation; +using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MatterControl.PrintQueue; using NUnit.Framework; +using System.Linq; namespace MatterHackers.MatterControl.Tests.Automation { @@ -65,34 +67,6 @@ namespace MatterHackers.MatterControl.Tests.Automation await MatterControlUtilities.RunTest(testToRun, queueItemFolderToAdd: QueueTemplate.Three_Queue_Items); } - [Test, Apartment(ApartmentState.STA)] - public async Task ClickingCreateButtonOpensPluginWindow() - { - AutomationTest testToRun = (testRunner) => - { - testRunner.CloseSignInAndPrinterSelect(); - // Tests that clicking the create button opens create tools plugin window - testRunner.CloseSignInAndPrinterSelect(); - - //Make sure that plugin window does not exist - bool pluginWindowExists1 = testRunner.WaitForName("Plugin Chooser Window", 0); - Assert.IsTrue(pluginWindowExists1 == false, "Plugin window does not exist"); - - testRunner.ClickByName("Design Tool Button", 5); - - //Test that the plugin window does exist after the create button is clicked - SystemWindow containingWindow; - GuiWidget pluginWindowExists = testRunner.GetWidgetByName("Plugin Chooser Window", out containingWindow, secondsToWait: 3); - Assert.IsTrue(pluginWindowExists != null, "Plugin Chooser Window"); - pluginWindowExists.CloseOnIdle(); - testRunner.Delay(.5); - - return Task.FromResult(0); - }; - - await MatterControlUtilities.RunTest(testToRun); - } - [Test, Apartment(ApartmentState.STA)] public async Task ClickOnExportButton() { @@ -515,6 +489,37 @@ namespace MatterHackers.MatterControl.Tests.Automation await MatterControlUtilities.RunTest(testToRun, queueItemFolderToAdd: QueueTemplate.Three_Queue_Items); } + [Test, Apartment(ApartmentState.STA)] + public async Task DragTo3DViewAddsItem() + { + AutomationTest testToRun = (testRunner) => + { + testRunner.CloseSignInAndPrinterSelect(); + + int queueItemCount = QueueData.Instance.ItemCount; + + bool queueItemExists = testRunner.WaitForName("Queue Item Batman", 2); + bool secondQueueItemExists = testRunner.WaitForName("Queue Item 2013-01-25_Mouthpiece_v2", 2); + + SystemWindow systemWindow; + GuiWidget partPreview = testRunner.GetWidgetByName("View3DWidget", out systemWindow, 3); + View3DWidget view3D = partPreview as View3DWidget; + + Assert.IsTrue(view3D.Scene.Children.Count() == 1); + testRunner.DragDropByName("Queue Item Batman", "centerPartPreviewAndControls"); + Assert.IsTrue(view3D.Scene.Children.Count() == 1); + + testRunner.ClickByName("3D View Edit"); + testRunner.DragDropByName("Queue Item Batman", "centerPartPreviewAndControls"); + + Assert.IsTrue(view3D.Scene.Children.Count() == 2); + + return Task.FromResult(0); + }; + + await MatterControlUtilities.RunTest(testToRun, queueItemFolderToAdd: QueueTemplate.Three_Queue_Items); + } + /// /// Confirms the Export to Zip feature compresses and exports to a zip file and that file imports without issue /// diff --git a/Tests/MatterControl.AutomationTests/SliceSettingsTests.cs b/Tests/MatterControl.AutomationTests/SliceSettingsTests.cs index afda5f03e..96cab509a 100644 --- a/Tests/MatterControl.AutomationTests/SliceSettingsTests.cs +++ b/Tests/MatterControl.AutomationTests/SliceSettingsTests.cs @@ -155,7 +155,7 @@ namespace MatterHackers.MatterControl.Tests.Automation return Task.FromResult(0); }; - await MatterControlUtilities.RunTest(testToRun, maxTimeToRun: 90); + await MatterControlUtilities.RunTest(testToRun, maxTimeToRun: 110); } private static void WaitForLayerAndResume(AutomationRunner testRunner, int indexToWaitFor) diff --git a/Tests/MatterControl.AutomationTests/SqLiteLibraryProvider.cs b/Tests/MatterControl.AutomationTests/SqLiteLibraryProvider.cs index 2401be90f..da9d8d3db 100644 --- a/Tests/MatterControl.AutomationTests/SqLiteLibraryProvider.cs +++ b/Tests/MatterControl.AutomationTests/SqLiteLibraryProvider.cs @@ -31,7 +31,9 @@ namespace MatterHackers.MatterControl.Tests.Automation GuiWidget partPreview = testRunner.GetWidgetByName("View3DWidget", out systemWindow, 3); View3DWidget view3D = partPreview as View3DWidget; - testRunner.ClickByName("3D View Edit", 3); + Assert.IsFalse(view3D.Scene.HasSelection); + testRunner.Select3DPart("Calibration - Box"); + Assert.IsTrue(view3D.Scene.HasSelection); testRunner.ClickByName("3D View Copy", 3); // wait for the copy to finish diff --git a/Tests/MatterControl.Tests/MatterControl.Tests.csproj b/Tests/MatterControl.Tests/MatterControl.Tests.csproj index dbf3d559d..3c3c321d0 100644 --- a/Tests/MatterControl.Tests/MatterControl.Tests.csproj +++ b/Tests/MatterControl.Tests/MatterControl.Tests.csproj @@ -71,6 +71,7 @@ + @@ -80,10 +81,6 @@ - - {70FBB82C-558D-4B5F-BE75-A922D392E650} - BrailleBuilder - {0B8D6F56-BD7F-4426-B858-D9292B084656} MatterControl @@ -96,10 +93,18 @@ {657DBC6D-C3EA-4398-A3FA-DDB73C14F71B} Agg + + {04667764-dc7b-4b95-aef6-b4e6c87a54e9} + DataConverters3D + {F67AE800-B0C7-42A8-836F-597B4E74591C} GCodeVisualizer + + {a737bc76-165b-46c6-82b7-8871c7c92942} + MeshViewer + {E9102310-0029-4D8F-B1E9-88FBA6147D45} GuiAutomation @@ -132,6 +137,10 @@ {D3E41B4E-BFBB-44CA-94C8-95C00F754FDD} VectorMath + + {F49EC1DD-D645-4709-8667-B57318AF67B0} + TextCreator + \ No newline at end of file diff --git a/Tests/MatterControl.Tests/MatterControl/MatterControlUtilities.cs b/Tests/MatterControl.Tests/MatterControl/MatterControlUtilities.cs index b25eaff53..4f51dd241 100644 --- a/Tests/MatterControl.Tests/MatterControl/MatterControlUtilities.cs +++ b/Tests/MatterControl.Tests/MatterControl/MatterControlUtilities.cs @@ -143,6 +143,18 @@ namespace MatterHackers.MatterControl.Tests.Automation CloseSignInAndPrinterSelect, }; + public static void Select3DPart(this AutomationRunner testRunner, string partNameToSelect) + { + if(testRunner.NameExists("3D View Edit")) + { + testRunner.ClickByName("3D View Edit"); + } + testRunner.DragDropByName("centerPartPreviewAndControls", "centerPartPreviewAndControls", offsetDrop: new Agg.Point2D(10, 15), mouseButtons: MouseButtons.Right); + + testRunner.Delay(1); + testRunner.ClickByName(partNameToSelect); + } + public static void CloseSignInAndPrinterSelect(this AutomationRunner testRunner, PrepAction preAction = PrepAction.CloseSignInAndPrinterSelect) { // Non-MCCentral builds won't have the plugin. Reduce the wait time for these cases diff --git a/Tests/MatterControl.Tests/MatterControl/PerformanceTests.cs b/Tests/MatterControl.Tests/MatterControl/PerformanceTests.cs index 96c0d9f18..0627cf6db 100644 --- a/Tests/MatterControl.Tests/MatterControl/PerformanceTests.cs +++ b/Tests/MatterControl.Tests/MatterControl/PerformanceTests.cs @@ -31,6 +31,7 @@ using MatterHackers.Agg; using MatterHackers.Agg.UI; using MatterHackers.GuiAutomation; using MatterHackers.MatterControl.Tests.Automation; +using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -45,43 +46,41 @@ namespace MatterHackers.MatterControl StatisticsTracker testTracker = new StatisticsTracker("SwitchBetweenTabs"); bool clickFirstItem = true; bool done = false; - bool firstDraw = true; AutomationRunner clickPreview; Stopwatch timeSinceLastClick = Stopwatch.StartNew(); Stopwatch totalDrawTime = Stopwatch.StartNew(); int drawCount = 0; - EventHandler beforeDraw = (sender, e) => + EventHandler formLoad = (s, e) => { - if (firstDraw) + clickPreview = new AutomationRunner(); + Task.Run(() => { - clickPreview = new AutomationRunner(); - Task.Run(() => + while (!done) { - while (!done) + if (clickPreview != null && timeSinceLastClick.Elapsed.TotalSeconds > switchTimeSeconds) { - if (clickPreview != null && timeSinceLastClick.Elapsed.TotalSeconds > switchTimeSeconds) + if (clickFirstItem) { - if (clickFirstItem) - { - clickPreview.ClickByName(firstWidgetName); - } - else - { - clickPreview.ClickByName(secondWidgetName); - } - clickFirstItem = !clickFirstItem; - timeSinceLastClick.Restart(); + clickPreview.ClickByName(firstWidgetName); } + else + { + clickPreview.ClickByName(secondWidgetName); + } + clickFirstItem = !clickFirstItem; + timeSinceLastClick.Restart(); } - }); - firstDraw = false; - } - - totalDrawTime.Restart(); + } + }); }; - container.BeforeDraw += beforeDraw; + container.Load += formLoad; + + container.BeforeDraw += (sender, e) => + { + totalDrawTime.Restart(); + }; EventHandler afterDraw = null; afterDraw = (sender, e) => @@ -93,7 +92,7 @@ namespace MatterHackers.MatterControl if (testTracker.Count == 100) { Trace.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(testTracker)); - container.BeforeDraw -= beforeDraw; + container.Load -= formLoad; container.BeforeDraw -= afterDraw; done = true; } diff --git a/Tests/MatterControl.Tests/MatterControl/ReleaseBuildTests.cs b/Tests/MatterControl.Tests/MatterControl/ReleaseBuildTests.cs index 217f72428..54553d78b 100644 --- a/Tests/MatterControl.Tests/MatterControl/ReleaseBuildTests.cs +++ b/Tests/MatterControl.Tests/MatterControl/ReleaseBuildTests.cs @@ -64,7 +64,6 @@ namespace MatterControl.Tests MatterHackers.Agg.ImageProcessing.dll MatterHackers.MarchingSquares.dll GuiAutomation.dll - BrailBuilder.dll TextCreator.dll"; foreach (string assemblyName in knownAssemblies.Split('\n').Select(s => s.Trim())) diff --git a/Tests/MatterControl.Tests/SceneTests.cs b/Tests/MatterControl.Tests/SceneTests.cs new file mode 100644 index 000000000..1d0d6e594 --- /dev/null +++ b/Tests/MatterControl.Tests/SceneTests.cs @@ -0,0 +1,175 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg.PlatformAbstract; +using MatterHackers.DataConverters3D; +using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.MeshVisualizer; +using MatterHackers.PolygonMesh.Csg; +using MatterHackers.VectorMath; +using Newtonsoft.Json; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using MatterHackers.MatterControl.Tests.Automation; +using MatterHackers.Agg; +using MatterHackers.MatterControl.SlicerConfiguration; + +namespace MatterHackers.PolygonMesh.UnitTests +{ + [TestFixture, Category("Agg.PolygonMesh")] + public class SceneTests + { + static string matterControlPath = Path.GetFullPath(Path.Combine("..", "..", "..", "..", "..", "MatterControl")); + + [Test] + public void SaveSimpleScene() + { + var scene = new InteractiveScene(); + scene.Children.Add(new Object3D + { + ItemType = Object3DTypes.Model + }); + + string tempPath = GetSceneTempPath(); + string filePath = Path.Combine(tempPath, "some.mcx"); + + scene.Save(filePath, tempPath); + + Assert.IsTrue(File.Exists(filePath)); + + IObject3D loadedItem = Object3D.Load(filePath); + Assert.IsTrue(loadedItem.Children.Count == 1); + } + + [Test] + public void CreatesAndLinksAmfsForUnsavedMeshes() + { + var scene = new InteractiveScene(); + scene.Children.Add(new Object3D + { + ItemType = Object3DTypes.Model, + Mesh = PlatonicSolids.CreateCube(20, 20, 20) + }); + + string tempPath = GetSceneTempPath(); + string filePath = Path.Combine(tempPath, "some.mcx"); + + scene.Save(filePath, tempPath); + + Assert.IsTrue(File.Exists(filePath)); + + IObject3D loadedItem = Object3D.Load(filePath); + Assert.IsTrue(loadedItem.Children.Count == 1); + + IObject3D meshItem = loadedItem.Children.First(); + + Assert.IsTrue(!string.IsNullOrEmpty(meshItem.MeshPath)); + Assert.IsTrue(File.Exists(meshItem.MeshPath)); + Assert.IsNotNull(meshItem.Mesh); + Assert.IsTrue(meshItem.Mesh.Faces.Count > 0); + } + + [Test] + public async Task ResavedSceneRemainsConsistent() + { +#if !__ANDROID__ + string staticDataPathOverride = Path.Combine(matterControlPath, "StaticData"); + + // Set the static data to point to the directory of MatterControl + StaticData.Instance = new FileSystemStaticData(TestContext.CurrentContext.ResolveProjectPath(4, "StaticData")); + MatterControlUtilities.OverrideAppDataLocation(TestContext.CurrentContext.ResolveProjectPath(4)); + + ActiveSliceSettings.Instance?.SetValue(SettingsKey.center_part_on_bed, "0"); +#endif + var view3DWidget = new View3DWidget( + null, + new Vector3(200, 200, 100), + new Vector2(100, 100), + MeshVisualizer.BedShape.Rectangular, + View3DWidget.WindowMode.Embeded, + View3DWidget.AutoRotate.Disabled, + View3DWidget.OpenMode.Editing); + + var scene = view3DWidget.Scene; + scene.Children.Add(new Object3D + { + ItemType = Object3DTypes.Model, + Mesh = PlatonicSolids.CreateCube(20, 20, 20) + }); + + string tempPath = GetSceneTempPath(); + string filePath = Path.Combine(tempPath, "some.mcx"); + + // Empty temp folder + foreach(string tempFile in Directory.GetFiles(tempPath).ToList()) + { + File.Delete(tempFile); + } + + scene.Save(filePath, tempPath); + Assert.AreEqual(1, Directory.GetFiles(tempPath).Length, "Only .mcx file should exists"); + Assert.AreEqual(1, Directory.GetFiles(Path.Combine(tempPath, "Assets")).Length, "Only 1 asset should exist"); + + var originalFiles = Directory.GetFiles(tempPath).ToArray(); ; + + IObject3D loadedItem = Object3D.Load(filePath); + Assert.IsTrue(loadedItem.Children.Count == 1); + + await view3DWidget.ClearBedAndLoadPrintItemWrapper( + new MatterControl.PrintQueue.PrintItemWrapper( + new MatterControl.DataStorage.PrintItem("test", filePath)), true); + + string onDiskData = JsonConvert.SerializeObject(loadedItem, Formatting.Indented); + string inMemoryData = JsonConvert.SerializeObject(view3DWidget.Scene, Formatting.Indented); + + Assert.IsTrue(inMemoryData == onDiskData); + + // Save the scene a second time, validate that things remain the same + view3DWidget.Scene.Save(filePath, tempPath); + onDiskData = JsonConvert.SerializeObject(loadedItem, Formatting.Indented); + + Assert.IsTrue(inMemoryData == onDiskData); + + // Verify that no additional files get created on second save + Assert.AreEqual(1, Directory.GetFiles(tempPath).Length, "Only .mcx file should exists"); + Assert.AreEqual(1, Directory.GetFiles(Path.Combine(tempPath, "Assets")).Length, "Only 1 asset should exist"); + } + + public static string GetSceneTempPath() + { + string tempPath = Path.GetFullPath(Path.Combine(matterControlPath, "Tests", "temp", "scenetests")); + Directory.CreateDirectory(tempPath); + return tempPath; + } + } +} \ No newline at end of file diff --git a/TextCreator/Braille/BrailleEditor.cs b/TextCreator/Braille/BrailleEditor.cs new file mode 100644 index 000000000..b9be7eedf --- /dev/null +++ b/TextCreator/Braille/BrailleEditor.cs @@ -0,0 +1,214 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg; +using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; +using MatterHackers.Localizations; +using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.PolygonMesh; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; + +namespace MatterHackers.MatterControl.Plugins.BrailleBuilder +{ + public class BrailleEditor : IObject3DEditor + { + private MHTextEditWidget textToAddWidget; + private CheckBox includeText; + private CheckBox useGrade2; + + private BrailleGenerator brailleGenerator; + private View3DWidget view3DWidget; + + private TextObject injectedItem = null; + + public IEnumerable SupportedTypes() + { + return new Type[] { typeof(TextObject) }; + } + + public GuiWidget Create(IObject3D item, View3DWidget parentView3D) + { + injectedItem = parentView3D.Scene?.SelectedItem as TextObject; + + brailleGenerator = new BrailleGenerator(); + this.view3DWidget = parentView3D; + + FlowLayoutWidget mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); + + FlowLayoutWidget tabContainer = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + HAnchor = HAnchor.AbsolutePosition, + Visible = true, + Width = view3DWidget.WhiteButtonFactory.FixedWidth + }; + mainContainer.AddChild(tabContainer); + + textToAddWidget = new MHTextEditWidget("", pixelWidth: 300, messageWhenEmptyAndNotSelected: "Enter Text Here".Localize()) + { + HAnchor = HAnchor.ParentLeftRight, + Margin = new BorderDouble(5), + Text = injectedItem.Text + }; + textToAddWidget.ActualTextEditWidget.EnterPressed += (s, e) => RebuildText(textToAddWidget.Text); + tabContainer.AddChild(textToAddWidget); + + includeText = new CheckBox(new CheckBoxViewText("Include Text".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor)) + { + ToolTipText = "Show normal text above the braille".Localize(), + Checked = false, + Margin = new BorderDouble(10, 5), + HAnchor = HAnchor.ParentLeft + }; + + tabContainer.AddChild(includeText); + includeText.CheckedStateChanged += (s, e) => RebuildText(textToAddWidget.Text); + + useGrade2 = new CheckBox(new CheckBoxViewText("Use Grade 2".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor)); + useGrade2.ToolTipText = "Experimental support for Braille grade 2 (contractions)".Localize(); + useGrade2.Checked = false; + useGrade2.Margin = new BorderDouble(10, 5); + useGrade2.HAnchor = HAnchor.ParentLeft; + tabContainer.AddChild(useGrade2); + useGrade2.CheckedStateChanged += (sender, e) => + { + RebuildText(textToAddWidget.Text); + }; + + Button updateButton = view3DWidget.textImageButtonFactory.Generate("Update".Localize()); + updateButton.Margin = new BorderDouble(5); + updateButton.HAnchor = HAnchor.ParentRight; + updateButton.Click += (s, e) => RebuildText(textToAddWidget.Text); + tabContainer.AddChild(updateButton); + + // put in a link to the wikipedia article + { + LinkButtonFactory linkButtonFactory = new LinkButtonFactory(); + linkButtonFactory.fontSize = 10; + linkButtonFactory.textColor = ActiveTheme.Instance.PrimaryTextColor; + + Button moreAboutBrailleLink = linkButtonFactory.Generate("About Braille".Localize()); + moreAboutBrailleLink.Margin = new BorderDouble(10, 5); + moreAboutBrailleLink.HAnchor = HAnchor.ParentLeft; + moreAboutBrailleLink.Click += (sender, e) => + { + UiThread.RunOnIdle(() => + { + MatterControlApplication.Instance.LaunchBrowser("https://en.wikipedia.org/wiki/Braille"); + }); + }; + + tabContainer.AddChild(moreAboutBrailleLink); + } + + return mainContainer; + } + + public string Name { get; } = "Braille"; + + private async void RebuildText(string brailleText) + { + injectedItem.Text = brailleText; + + if (brailleText.Length <= 0) + { + return; + } + + if (useGrade2.Checked) + { + brailleText = BrailleGrade2.ConvertString(brailleText); + } + + brailleGenerator.ResetSettings(); + + //processingProgressControl.ProcessType = "Inserting Text".Localize(); + //processingProgressControl.Visible = true; + //processingProgressControl.PercentComplete = 0; + + view3DWidget.LockEditControls(); + + var generatedItem = await Task.Run(() => + { + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + + return brailleGenerator.CreateText( + brailleText, + 1, + 1, + includeText.Checked, + injectedItem.Text); + }); + + view3DWidget.Scene.ModifyChildren(children => + { + // Find the injected item + var item = children.Find(child => child == injectedItem); + + // Clear and refresh its children + item.Children.Clear(); + item.Children.AddRange(generatedItem.Children); + }); + + //PlatingHelper.MoveToOpenPosition(injectedItem, view3DWidget.Scene); + + //view3DWidget.InsertNewItem(injectedItem); + + view3DWidget.UnlockEditControls(); + } + + private void RebuildBase() + { + if (view3DWidget.Scene.HasChildren && injectedItem != null) + { + var newBaseplate = brailleGenerator.CreateBaseplate(injectedItem); + if(newBaseplate == null) + { + return; + } + + // Remove the old base and create and add a new one + view3DWidget.Scene.ModifyChildren(children => + { + children.RemoveAll(child => child is BraileBasePlate); + children.Add(newBaseplate); + }); + } + } + + internal void SetInitialFocus() + { + textToAddWidget.Focus(); + } + } +} \ No newline at end of file diff --git a/TextCreator/Braille/BrailleGenerator.cs b/TextCreator/Braille/BrailleGenerator.cs new file mode 100644 index 000000000..ffbc32ff4 --- /dev/null +++ b/TextCreator/Braille/BrailleGenerator.cs @@ -0,0 +1,266 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg; +using MatterHackers.Agg.Font; +using MatterHackers.Agg.PlatformAbstract; +using MatterHackers.Agg.VertexSource; +using MatterHackers.DataConverters3D; +using MatterHackers.PolygonMesh; +using MatterHackers.VectorMath; +using System.IO; +using System.Linq; + +namespace MatterHackers.MatterControl.Plugins.BrailleBuilder +{ + public class BrailleGenerator + { + private double lastHeightValue = 1; + private double lastSizeValue = 1; + + private TypeFace brailTypeFace; + private TypeFace boldTypeFace; + + private const double unscaledBaseHeight = 7; + private const double unscaledLetterHeight = 3; + + public BrailleGenerator() + { + boldTypeFace = TypeFace.LoadFrom(StaticData.Instance.ReadAllText(Path.Combine("Fonts", "LiberationMono.svg"))); + brailTypeFace = TypeFace.LoadFrom(StaticData.Instance.ReadAllText(Path.Combine("Fonts", "Braille.svg"))); + } + + public IObject3D CreateText(string brailleText, double wordSize, double wordHeight, bool includeText = false, string wordText = null) + { + var group = new TextObject + { + ItemType = Object3DTypes.Group, + Text = wordText, + ActiveEditor = "BrailleEditor" + }; + + TypeFacePrinter brailPrinter = new TypeFacePrinter(brailleText, new StyledTypeFace(brailTypeFace, 12)); + + StyledTypeFace boldStyled = new StyledTypeFace(boldTypeFace, 12); + + if (includeText) + { + TypeFacePrinter normalPrinter = new TypeFacePrinter(wordText, boldStyled); + Vector2 normalSize = normalPrinter.GetSize(); + AddCharacterMeshes(group, wordText, normalPrinter); + } + + AddCharacterMeshes(group, brailleText, brailPrinter); + Vector2 brailSize = brailPrinter.GetSize(); + + foreach (var object3D in group.Children) + { + object3D.ExtraData.Spacing += new Vector2(0, boldStyled.CapHeightInPixels * 1.5); + } + + IObject3D basePlate = CreateBaseplate(group); + group.Children.Add(basePlate); + + SetCharacterPositions(group); + SetWordSize(group, wordSize); + SetWordHeight(group, wordHeight); + + // Remove the temporary baseplate added above and required by SetPositions/SetSize + group.Children.Remove(basePlate); + + // Add the actual baseplate that can be correctly sized to its siblings bounds + basePlate = CreateBaseplate(group); + group.Children.Add(basePlate); + + return group; + } + + private void AddCharacterMeshes(IObject3D group, string currentText, TypeFacePrinter printer) + { + StyledTypeFace typeFace = printer.TypeFaceStyle; + + for (int i = 0; i < currentText.Length; i++) + { + string letter = currentText[i].ToString(); + TypeFacePrinter letterPrinter = new TypeFacePrinter(letter, typeFace); + + if (CharacterHasMesh(letterPrinter, letter)) + { +#if true + Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2); +#else + Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2); + // this is the code to make rounded tops + // convert the letterPrinter to clipper polygons + List> insetPoly = VertexSourceToPolygon.CreatePolygons(letterPrinter); + // inset them + ClipperOffset clipper = new ClipperOffset(); + clipper.AddPaths(insetPoly, JoinType.jtMiter, EndType.etClosedPolygon); + List> solution = new List>(); + clipper.Execute(solution, 5.0); + // convert them back into a vertex source + // merge both the inset and original vertex sources together + // convert the new vertex source into a mesh (triangulate them) + // offset the inner loop in z + // create the polygons from the inner loop to a center point so that there is the rest of an approximation of the bubble + // make the mesh for the bottom + // add the top and bottom together + // done +#endif + var characterObject = new Object3D() + { + Mesh = textMesh, + ItemType = Object3DTypes.Model + }; + + characterObject.ExtraData.Spacing = printer.GetOffsetLeftOfCharacterIndex(i); + characterObject.Matrix *= Matrix4X4.CreateTranslation(new Vector3(0, 0, unscaledLetterHeight / 2)); + + group.Children.Add(characterObject); + } + + //processingProgressControl.PercentComplete = ((i + 1) * 95 / currentText.Length); + } + } + + private void SetCharacterPositions(IObject3D group) + { + if (group.HasChildren) + { + foreach (IObject3D child in group.Children) + { + Vector3 startPosition = Vector3.Transform(Vector3.Zero, child.Matrix); + //child.Matrix *= Matrix4X4.CreateTranslation(-startPosition); + + double newX = child.ExtraData.Spacing.x * lastSizeValue; + double newY = child.ExtraData.Spacing.y * lastSizeValue; + + child.Matrix *= Matrix4X4.CreateTranslation(new Vector3(newX, newY, startPosition.z)); + } + } + } + + public void SetWordHeight(IObject3D group, double newHeight) + { + if (group.HasChildren) + { + AxisAlignedBoundingBox baseBounds = group.Children.Last().GetAxisAlignedBoundingBox(Matrix4X4.Identity); + + // Skip the base item + foreach (var sceneItem in group.Children.Take(group.Children.Count - 1)) + { + Vector3 startPosition = Vector3.Transform(Vector3.Zero, sceneItem.Matrix); + + // take out the last scale + double oldHeight = 1.0 / lastHeightValue; + + // move the part to keep it in the same relative position + sceneItem.Matrix *= Matrix4X4.CreateScale(new Vector3(1, 1, oldHeight)); + sceneItem.Matrix *= Matrix4X4.CreateScale(new Vector3(1, 1, newHeight)); + + sceneItem.Matrix *= Matrix4X4.CreateTranslation(new Vector3(0, 0, baseBounds.ZSize - startPosition.z)); + } + + lastHeightValue = newHeight; + } + } + + public void SetWordSize(IObject3D group, double newSize) + { + if (group.HasChildren) + { + foreach (var object3D in group.Children) + { + Vector3 startPositionRelCenter = Vector3.Transform(Vector3.Zero, object3D.Matrix); + + // take out the last scale + double oldSize = 1.0 / lastSizeValue; + Vector3 unscaledStartPositionRelCenter = startPositionRelCenter * oldSize; + + Vector3 endPositionRelCenter = unscaledStartPositionRelCenter * newSize; + + Vector3 deltaPosition = endPositionRelCenter - startPositionRelCenter; + + // move the part to keep it in the same relative position + object3D.Matrix *= Matrix4X4.CreateScale(new Vector3(oldSize, oldSize, oldSize)); + object3D.Matrix *= Matrix4X4.CreateScale(new Vector3(newSize, newSize, newSize)); + object3D.Matrix *= Matrix4X4.CreateTranslation(deltaPosition); + } + + lastSizeValue = newSize; + } + } + private bool CharacterHasMesh(TypeFacePrinter letterPrinter, string letter) + { + return letterPrinter.LocalBounds.Width > 0 + && letter != " " + && letter != "\n"; + } + + public IObject3D CreateBaseplate(IObject3D group) + { + if (group.HasChildren) + { + AxisAlignedBoundingBox bounds = group.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + + double roundingScale = 20; + RectangleDouble baseRect = new RectangleDouble(bounds.minXYZ.x, bounds.minXYZ.y, bounds.maxXYZ.x, bounds.maxXYZ.y); + baseRect.Inflate(2); + baseRect *= roundingScale; + + RoundedRect baseRoundedRect = new RoundedRect(baseRect, 1 * roundingScale); + Mesh baseMeshResult = VertexSourceToMesh.Extrude(baseRoundedRect, unscaledBaseHeight / 2 * roundingScale * lastHeightValue); + baseMeshResult.Transform(Matrix4X4.CreateScale(1 / roundingScale)); + + var basePlateObject = new BraileBasePlate() + { + Mesh = baseMeshResult, + ItemType = Object3DTypes.Model + }; + + basePlateObject.Matrix *= Matrix4X4.CreateTranslation(new Vector3(0, 0, 0)); + + return basePlateObject; + } + + return null; + } + + public void ResetSettings() + { + lastHeightValue = 1; + lastSizeValue = 1; + } + } + + public class BraileBasePlate : Object3D + { + } + +} \ No newline at end of file diff --git a/BrailleBuilder/BrailleGrade2.cs b/TextCreator/Braille/BrailleGrade2.cs similarity index 100% rename from BrailleBuilder/BrailleGrade2.cs rename to TextCreator/Braille/BrailleGrade2.cs diff --git a/BrailleBuilder/BrailleGrade2Mapping.cs b/TextCreator/Braille/BrailleGrade2Mapping.cs similarity index 100% rename from BrailleBuilder/BrailleGrade2Mapping.cs rename to TextCreator/Braille/BrailleGrade2Mapping.cs diff --git a/TextCreator/CardHolderTool/CardHolder.cs b/TextCreator/CardHolderTool/CardHolder.cs new file mode 100644 index 000000000..96ecd7699 --- /dev/null +++ b/TextCreator/CardHolderTool/CardHolder.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using MatterHackers.Csg; +using MatterHackers.Agg.Font; +using MatterHackers.Csg.Solids; +using MatterHackers.Csg.Transform; +using MatterHackers.Csg.Processors; +using MatterHackers.VectorMath; +using MatterHackers.RenderOpenGl; +using MatterHackers.DataConverters3D; +using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.Agg.UI; +using MatterHackers.MatterControl; +using MatterHackers.Localizations; +using MatterHackers.Agg; +using MatterHackers.MatterControl.CustomWidgets; +using System.Linq; + +namespace MatterHackers.MatterControl.SimplePartScripting +{ + public abstract class MatterCadObject3D : Object3D + { + public override string ActiveEditor { get; set; } = "MatterCadEditor"; + + public virtual MatterHackers.PolygonMesh.Mesh Create() + { + return Mesh; + } + } + + public class MatterCadEditor : IObject3DEditor + { + private View3DWidget view3DWidget; + private IObject3D item; + + public string Name => "MatterCad"; + + public IEnumerable SupportedTypes() => new Type[] + { + typeof(MatterCadObject3D), + }; + + public GuiWidget Create(IObject3D item, View3DWidget view3DWidget) + { + this.view3DWidget = view3DWidget; + this.item = item; + + var mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); + + var tabContainer = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + HAnchor = HAnchor.AbsolutePosition, + Visible = true, + Width = view3DWidget.WhiteButtonFactory.FixedWidth + }; + mainContainer.AddChild(tabContainer); + + if (item is MatterCadObject3D) + { + ModifyCadObject(view3DWidget, tabContainer); + } + return mainContainer; + } + + private void ModifyCadObject(View3DWidget view3DWidget, FlowLayoutWidget tabContainer) + { + var stringPropertyNamesAndValues = this.item.GetType() + .GetProperties() + .Where(pi => pi.PropertyType == typeof(Double) && pi.GetGetMethod() != null) + .Select(pi => new + { + Name = pi.Name, + Value = pi + }); + + foreach (var nameValue in stringPropertyNamesAndValues) + { + FlowLayoutWidget rowContainer = CreateSettingsRow(nameValue.Name.Localize()); + var doubleEditWidget = new MHNumberEdit((double)nameValue.Value.GetGetMethod().Invoke(this.item, null), pixelWidth: 50 * GuiWidget.DeviceScale, allowNegatives: true, allowDecimals: true, increment: .05) + { + SelectAllOnFocus = true, + VAnchor = VAnchor.ParentCenter + }; + doubleEditWidget.ActuallNumberEdit.EditComplete += (s, e) => + { + double editValue; + if (double.TryParse(doubleEditWidget.Text, out editValue)) + { + nameValue.Value.GetSetMethod().Invoke(this.item, new Object[] { editValue }); + } + this.item.SetAndInvalidateMesh(((MatterCadObject3D)item).Create()); + }; + rowContainer.AddChild(doubleEditWidget); + tabContainer.AddChild(rowContainer); + } + + var updateButton = view3DWidget.textImageButtonFactory.Generate("Update".Localize()); + updateButton.Margin = new BorderDouble(5); + updateButton.HAnchor = HAnchor.ParentRight; + updateButton.Click += (s, e) => + { + this.item.SetAndInvalidateMesh(((MatterCadObject3D)item).Create()); + }; + tabContainer.AddChild(updateButton); + } + + private static FlowLayoutWidget CreateSettingsRow(string labelText) + { + var rowContainer = new FlowLayoutWidget(FlowDirection.LeftToRight) + { + HAnchor = HAnchor.ParentLeftRight, + Padding = new BorderDouble(5) + }; + + var label = new TextWidget(labelText + ":", textColor: ActiveTheme.Instance.PrimaryTextColor) + { + Margin = new BorderDouble(0, 0, 3, 0), + VAnchor = VAnchor.ParentCenter + }; + rowContainer.AddChild(label); + + rowContainer.AddChild(new HorizontalSpacer()); + + return rowContainer; + } + } + + public class TestPart : MatterCadObject3D, IMappingType + { + public string TypeName { get; } = nameof(TestPart); + public string FullTypeName { get; } = "MatterHackers.MatterControl.SimplePartScripting.TestPart,TextCreator"; + + public double XOffset { get; set; } = -.4; + + public TestPart() + { + Mesh = Create(); + } + + public override MatterHackers.PolygonMesh.Mesh Create() + { + CsgObject boxCombine = new Box(10, 10, 10); + boxCombine -= new Translate(new Box(10, 10, 10), XOffset, -3, 2); + return CsgToMesh.Convert(boxCombine); + } + } + + public class CardHolder : MatterCadObject3D, IMappingType + { + public string TypeName { get; } = nameof(CardHolder); + public string FullTypeName { get; } = "MatterHackers.MatterControl.SimplePartScripting.CardHolder,TextCreator"; + + // these are the public variables that would be edited + public string Name { get; set; } = "Name"; + + public MatterHackers.PolygonMesh.Mesh Create() + { + CsgObject plainCardHolder = new MeshContainer("PlainBusinessCardHolder.stl"); + + TypeFace typeFace = TypeFace.LoadSVG("Viking_n.svg"); + + TypeFacePrinter letterPrinter = new TypeFacePrinter(Name, new StyledTypeFace(typeFace, 12)); + MatterHackers.PolygonMesh.Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, 5); + + CsgObject nameMesh = new MeshContainer(textMesh); + + AxisAlignedBoundingBox textBounds = textMesh.GetAxisAlignedBoundingBox(); + Vector2 textArea = new Vector2(85, 20); + + nameMesh = new Box(textArea.x, textArea.y, 5); + + + double scale = Math.Min(textArea.x / textBounds.XSize, textArea.y / textBounds.YSize); + nameMesh = new Scale(nameMesh, scale, scale, 1); + nameMesh = new Align(nameMesh, Face.Top | Face.Front, plainCardHolder, Face.Bottom | Face.Front); + nameMesh = new SetCenter(nameMesh, plainCardHolder.GetCenter(), true, false, false); + + nameMesh = new Rotate(nameMesh, MathHelper.DegreesToRadians(18)); + nameMesh = new Translate(nameMesh, 0, 2, 16); + + plainCardHolder += nameMesh; + + return CsgToMesh.Convert(plainCardHolder); + } + } + + public class ChairFoot : MatterCadObject3D, IMappingType + { + public string TypeName { get; } = nameof(ChairFoot); + public string FullTypeName { get; } = "MatterHackers.MatterControl.SimplePartScripting.ChairFoot,TextCreator"; + + // these are the public variables that would be edited + public bool FinalPart { get; set; } = true; + + public double HeightFromFloorToBottomOfLeg { get; set; } = 10; + + public double OuterSize { get; set; } = 22; + + public double InnerSize { get; set; } = 20; + public double InsideReach { get; set; } = 10; + + public double AngleDegrees { get; set; } = 3; + + public ChairFoot() + { + Mesh = Create(); + } + + public override MatterHackers.PolygonMesh.Mesh Create() + { + // This would be better expressed as the desired offset height (height from ground to bottom of chair leg). + double angleRadians = MathHelper.DegreesToRadians(AngleDegrees); + double extraHeightForRotation = Math.Sinh(angleRadians) * OuterSize; // get the distance to clip off the extra bottom + double unclippedFootHeight = HeightFromFloorToBottomOfLeg + extraHeightForRotation; + + if(FinalPart) + { + Box chairFootBox = new Box(OuterSize, OuterSize, unclippedFootHeight); + //chairFootBox.BevelEdge(Edge.LeftBack, 2); + //chairFootBox.BevelEdge(Edge.LeftFront, 2); + //chairFootBox.BevelEdge(Edge.RightBack, 2); + //chairFootBox.BevelEdge(Edge.RightFront, 2); + CsgObject chairFoot = chairFootBox; + + CsgObject ring = new Cylinder(InnerSize / 2 - 1, InsideReach); + ring -= new Cylinder(ring.XSize / 2 - 2, ring.ZSize + 1); + + CsgObject fins = new Box(3, 1, ring.ZSize); + fins = new Translate(fins, 0, 1) + new Translate(fins, 0, -1); + fins -= new Align(new Rotate(new Box(5, 5, 5), 0, MathHelper.DegreesToRadians(45)), Face.Bottom | Face.Left, fins, Face.Top | Face.Left, 0, 0, -fins.XSize); + fins = new Translate(fins, InnerSize / 2 - .1); + + ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45)); + ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 + 90)); + ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 + 180)); + ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 - 90)); + + chairFoot += new Align(ring, Face.Bottom, chairFoot, Face.Top, 0, 0, -.1); + + chairFoot = new Rotate(chairFoot, 0, angleRadians, 0); + CsgObject clipBox = new Align(new Box(OuterSize * 2, OuterSize * 2, unclippedFootHeight), Face.Top, chairFoot, Face.Bottom, 0, 0, extraHeightForRotation); + chairFoot -= clipBox; + chairFoot = new Translate(chairFoot, 0, 0, clipBox.GetAxisAlignedBoundingBox().maxXYZ.z); + + return CsgToMesh.Convert(chairFoot); + } + else // fit part + { + double baseHeight = 3; + double insideHeight = 4; + Box chairFootBox = new Box(OuterSize, OuterSize, baseHeight); + chairFootBox.BevelEdge(Edge.LeftBack, 2); + chairFootBox.BevelEdge(Edge.LeftFront, 2); + chairFootBox.BevelEdge(Edge.RightBack, 2); + chairFootBox.BevelEdge(Edge.RightFront, 2); + CsgObject chairFoot = chairFootBox; + + CsgObject ring = new Cylinder(InnerSize / 2 - 1, insideHeight); + ring -= new Cylinder(ring.XSize / 2 - 2, ring.ZSize + 1); + + CsgObject fins = new Box(3, 1, ring.ZSize); + fins = new Translate(fins, 0, 1) + new Translate(fins, 0, -1); + fins -= new Align(new Rotate(new Box(5, 5, 5), 0, MathHelper.DegreesToRadians(45)), Face.Bottom | Face.Left, fins, Face.Top | Face.Left, 0, 0, -fins.XSize); + fins = new Translate(fins, InnerSize / 2 - .1); + + ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45)); + ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 + 90)); + ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 + 180)); + ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 - 90)); + + chairFoot += new Align(ring, Face.Bottom, chairFoot, Face.Top, 0, 0, -.1); + + return CsgToMesh.Convert(chairFoot); + } + } + } +} diff --git a/TextCreator/SidebarPlugins/TextCreatorsSidebar.cs b/TextCreator/SidebarPlugins/TextCreatorsSidebar.cs new file mode 100644 index 000000000..af05a455b --- /dev/null +++ b/TextCreator/SidebarPlugins/TextCreatorsSidebar.cs @@ -0,0 +1,111 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg; +using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; +using MatterHackers.Localizations; +using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.MatterControl.Plugins.BrailleBuilder; +using MatterHackers.PolygonMesh; +using MatterHackers.PolygonMesh.Processors; +using System.Collections.Generic; + +namespace MatterHackers.MatterControl.Plugins.TextCreator +{ + public class TextCreatorsSidebar : SideBarPlugin + { + private static IObject3D textItem; + private static IObject3D brailleItem; + + public override GuiWidget CreateSideBarTool(View3DWidget view3DWidget) + { + FlowLayoutWidget mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); + + var tabButton = view3DWidget.ExpandMenuOptionFactory.GenerateCheckBoxButton("TEXT".Localize().ToUpper(), + View3DWidget.ArrowRight, + View3DWidget.ArrowDown); + tabButton.Margin = new BorderDouble(bottom: 2); + mainContainer.AddChild(tabButton); + + FlowLayoutWidget tabContainer = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + HAnchor = HAnchor.ParentLeftRight, + Visible = false + }; + mainContainer.AddChild(tabContainer); + + tabButton.CheckedStateChanged += (sender, e) => + { + tabContainer.Visible = tabButton.Checked; + }; + + FlowLayoutWidget buttonRow = new FlowLayoutWidget(FlowDirection.LeftToRight); + buttonRow.AddChild( + view3DWidget.Sidebar.CreateAddButton("Text".Localize(), "textcreator.png", () => + { + if(textItem == null) + { + var generator = new TextGenerator(); + textItem = generator.CreateText( + "Text".Localize(), + 1, + .25, + 1, + true); + } + + return textItem; + })); + + buttonRow.AddChild( + view3DWidget.Sidebar.CreateAddButton("Braille".Localize(), "braillecreator.png", () => + { + if (brailleItem == null) + { + string braille = "Braille".Localize(); + + var generator = new BrailleGenerator(); + brailleItem = generator.CreateText( + braille, + 1, + .25, + true, + braille); + } + + return brailleItem; + })); + + tabContainer.AddChild(buttonRow); + + return mainContainer; + } + } +} \ No newline at end of file diff --git a/TextCreator/Text/TextEditor.cs b/TextCreator/Text/TextEditor.cs new file mode 100644 index 000000000..e23449806 --- /dev/null +++ b/TextCreator/Text/TextEditor.cs @@ -0,0 +1,201 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg; +using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; +using MatterHackers.Localizations; +using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.PolygonMesh; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; + +namespace MatterHackers.MatterControl.Plugins.TextCreator +{ + public class TextEditor : IObject3DEditor + { + private MHTextEditWidget textToAddWidget; + private SolidSlider spacingScrollBar; + private CheckBox createUnderline; + + private TextGenerator textGenerator; + private View3DWidget view3DWidget; + + private TextObject injectedItem = null; + + public IEnumerable SupportedTypes() + { + return new Type[] { typeof(TextObject) }; + } + + public GuiWidget Create(IObject3D item, View3DWidget parentView3D) + { + injectedItem = parentView3D.Scene?.SelectedItem as TextObject; + + textGenerator = new TextGenerator(); + this.view3DWidget = parentView3D; + + FlowLayoutWidget mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); + + FlowLayoutWidget tabContainer = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + HAnchor = HAnchor.AbsolutePosition, + Visible = true, + Width = view3DWidget.WhiteButtonFactory.FixedWidth + }; + mainContainer.AddChild(tabContainer); + + textToAddWidget = new MHTextEditWidget("", messageWhenEmptyAndNotSelected: "Text".Localize()) + { + HAnchor = HAnchor.ParentLeftRight, + Margin = new BorderDouble(5), + Text = injectedItem.Text, + Width = 50 + }; + textToAddWidget.ActualTextEditWidget.EnterPressed += (s, e) => RebuildText(textToAddWidget.Text); + tabContainer.AddChild(textToAddWidget); + + spacingScrollBar = PartPreview3DWidget.InsertUiForSlider(tabContainer, "Spacing:".Localize(), .5, 1); + spacingScrollBar.ValueChanged += (sender, e) => + { + if (injectedItem != null) + { + textGenerator.SetWordSpacing(injectedItem, spacingScrollBar.Value, rebuildUnderline: true); + } + }; + + createUnderline = new CheckBox(new CheckBoxViewText("Underline".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor)) + { + Checked = true, + Margin = new BorderDouble(10, 5), + HAnchor = HAnchor.ParentLeft + }; + createUnderline.CheckedStateChanged += CreateUnderline_CheckedStateChanged; + tabContainer.AddChild(createUnderline); + + Button updateButton = view3DWidget.textImageButtonFactory.Generate("Update".Localize()); + updateButton.Margin = new BorderDouble(5); + updateButton.HAnchor = HAnchor.ParentRight; + updateButton.Click += (s, e) => RebuildText(textToAddWidget.Text); + tabContainer.AddChild(updateButton); + + return mainContainer; + } + + public string Name { get; } = "Text"; + + private void ResetWordLayoutSettings() + { + spacingScrollBar.Value = 1; + textGenerator.ResetSettings(); + } + + private async void RebuildText(string text) + { + injectedItem.Text = text; + + // Clear prior selection + + if (text.Length <= 0) + { + return; + } + + ResetWordLayoutSettings(); + + //view3DWidget.processingProgressControl.ProcessType = "Inserting Text".Localize(); + //view3DWidget.processingProgressControl.Visible = true; + //view3DWidget.processingProgressControl.PercentComplete = 0; + + view3DWidget.LockEditControls(); + + var generatedItem = await Task.Run(() => + { + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + + return textGenerator.CreateText( + text, + 1, + .25, + spacingScrollBar.Value, + createUnderline.Checked); + }); + + view3DWidget.Scene.ModifyChildren(children => + { + var item = children.Find(child => child == injectedItem); + item.Children.Clear(); + item.Children.AddRange(generatedItem.Children); + }); + + //PlatingHelper.MoveToOpenPosition(injectedItem, view3DWidget.Scene); + + //view3DWidget.InsertNewItem(injectedItem); + + view3DWidget.UnlockEditControls(); + } + + private void CreateUnderline_CheckedStateChanged(object sender, EventArgs e) + { + ModifyInjectedItem(workItem => + { + // Change the contents, adding or removing the underline + textGenerator.EnableUnderline(workItem, enableUnderline: createUnderline.Checked); + }); + } + + private void ModifyInjectedItem(Action modifier) + { + // Create a copy of the injected group + IObject3D workItem = injectedItem.Clone(); + + // Invoke the passed in action + modifier(workItem); + + // Modify the scene graph, swapping in the modified item + view3DWidget.Scene.ModifyChildren(children => + { + children.Remove(injectedItem); + children.Add(workItem); + }); + + // Update the injected item and the scene selection + injectedItem = workItem as TextObject; + view3DWidget.Scene.Select(injectedItem); + } + + internal void SetInitialFocus() + { + textToAddWidget.Focus(); + } + } +} \ No newline at end of file diff --git a/TextCreator/Text/TextGenerator.cs b/TextCreator/Text/TextGenerator.cs new file mode 100644 index 000000000..b0a8933c7 --- /dev/null +++ b/TextCreator/Text/TextGenerator.cs @@ -0,0 +1,242 @@ +/* +Copyright (c) 2016, 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 MatterHackers.Agg.Font; +using MatterHackers.Agg.PlatformAbstract; +using MatterHackers.DataConverters3D; +using MatterHackers.MeshVisualizer; +using MatterHackers.PolygonMesh; +using MatterHackers.VectorMath; +using System.IO; +using System.Linq; + +namespace MatterHackers.MatterControl.Plugins.TextCreator +{ + public class TextGenerator + { + private double lastHeightValue = 1; + private double lastSizeValue = 1; + private bool hasUnderline; + + private TypeFace boldTypeFace; + + public TextGenerator() + { + boldTypeFace = TypeFace.LoadFrom(StaticData.Instance.ReadAllText(Path.Combine("Fonts", "LiberationSans-Bold.svg"))); + } + + public IObject3D CreateText(string wordText, double wordSize, double wordHeight, double characterSpacing, bool createUnderline) + { + var groupItem = new TextObject() + { + ItemType = Object3DTypes.Group, + Text = wordText, + Spacing = characterSpacing, + ActiveEditor = "TextEditor" + }; + + StyledTypeFace typeFace = new StyledTypeFace(boldTypeFace, 12); + TypeFacePrinter printer = new TypeFacePrinter(wordText, typeFace); + + Vector2 size = printer.GetSize(wordText); + double centerOffset = -size.x / 2; + + double ratioPerMeshGroup = 1.0 / wordText.Length; + double currentRatioDone = 0; + + for (int i = 0; i < wordText.Length; i++) + { + string letter = wordText[i].ToString(); + TypeFacePrinter letterPrinter = new TypeFacePrinter(letter, typeFace); + + Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, 10 + (i % 2)); + if (textMesh.Faces.Count > 0) + { + var characterObject = new Object3D() + { + Mesh = textMesh, + ItemType = Object3DTypes.Model + }; + characterObject.ExtraData.Spacing.x = printer.GetOffsetLeftOfCharacterIndex(i).x + centerOffset; + + groupItem.Children.Add(characterObject); + + //public static void PlaceMeshGroupOnBed(List meshesGroupList, List meshTransforms, int index) + { + AxisAlignedBoundingBox bounds = characterObject.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + Vector3 boundsCenter = (bounds.maxXYZ + bounds.minXYZ) / 2; + + characterObject.Matrix *= Matrix4X4.CreateTranslation(new Vector3(0, 0, -boundsCenter.z + bounds.ZSize / 2)); + } + + currentRatioDone += ratioPerMeshGroup; + } + + //processingProgressControl.PercentComplete = ((i + 1) * 95 / wordText.Length); + } + + SetWordSpacing(groupItem, characterSpacing); + SetWordSize(groupItem, wordSize); + SetWordHeight(groupItem, wordHeight); + + if (createUnderline) + { + groupItem.Children.Add(CreateUnderline(groupItem)); + } + + // jlewin - restore progress + //processingProgressControl.PercentComplete = 95; + + return groupItem; + } + + private IObject3D CreateUnderline(IObject3D group) + { + if (group.HasChildren) + { + AxisAlignedBoundingBox bounds = group.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + + double xSize = bounds.XSize; + double ySize = lastSizeValue * 3; + double zSize = bounds.ZSize / 3; + + var lineObject = new Object3D() + { + Mesh = PlatonicSolids.CreateCube(xSize, ySize, zSize), + ItemType = Object3DTypes.Model, + Matrix = Matrix4X4.CreateTranslation((bounds.maxXYZ.x + bounds.minXYZ.x) / 2, bounds.minXYZ.y + ySize / 2 - ySize * 1 / 3, zSize / 2) + }; + + return lineObject; + } + + return null; + } + + public void EnableUnderline(IObject3D group, bool enableUnderline) + { + hasUnderline = enableUnderline; + + if (enableUnderline && group.HasChildren) + { + // we need to add the underline + group.Children.Add(CreateUnderline(group)); + } + else if (group.HasChildren) + { + // we need to remove the underline + group.Children.Remove(group.Children.Last()); + } + } + + public void RebuildUnderline(IObject3D group) + { + if (hasUnderline && group.HasChildren) + { + // Remove the underline object + group.Children.Remove(group.Children.Last()); + + // we need to add the underline + group.Children.Add(CreateUnderline(group)); + } + } + + public void SetWordSpacing(IObject3D group, double spacing, bool rebuildUnderline = false) + { + if (group.HasChildren) + { + foreach (var sceneItem in group.Children) + { + Vector3 startPosition = Vector3.Transform(Vector3.Zero, sceneItem.Matrix); + + sceneItem.Matrix *= Matrix4X4.CreateTranslation(-startPosition); + + double newX = sceneItem.ExtraData.Spacing.x * spacing * lastSizeValue; + sceneItem.Matrix *= Matrix4X4.CreateTranslation(new Vector3(newX, 0, 0) + new Vector3(MeshViewerWidget.BedCenter)); + } + + if (rebuildUnderline) + { + RebuildUnderline(group); + } + } + } + + public void SetWordSize(IObject3D group, double newSize, bool rebuildUnderline = false) + { + // take out the last scale + double oldSize = 1.0 / lastSizeValue; + + Vector3 bedCenter = new Vector3(MeshViewerWidget.BedCenter); + if (group.HasChildren) + { + foreach (var object3D in group.Children) + { + object3D.Matrix = PlatingHelper.ApplyAtPosition(object3D.Matrix, Matrix4X4.CreateScale(new Vector3(oldSize, oldSize, oldSize)), new Vector3(bedCenter)); + object3D.Matrix = PlatingHelper.ApplyAtPosition(object3D.Matrix, Matrix4X4.CreateScale(new Vector3(newSize, newSize, newSize)), new Vector3(bedCenter)); + } + + lastSizeValue = newSize; + + if (rebuildUnderline) + { + RebuildUnderline(group); + } + } + } + + public void SetWordHeight(IObject3D group, double newHeight, bool rebuildUnderline = false) + { + if (group.HasChildren) + { + foreach (var sceneItem in group.Children) + { + // take out the last scale + double oldHeight = lastHeightValue; + sceneItem.Matrix *= Matrix4X4.CreateScale(new Vector3(1, 1, 1 / oldHeight)); + + sceneItem.Matrix *= Matrix4X4.CreateScale(new Vector3(1, 1, newHeight)); + } + + lastHeightValue = newHeight; + + if (rebuildUnderline) + { + RebuildUnderline(group); + } + } + } + + public void ResetSettings() + { + lastHeightValue = 1; + lastSizeValue = 1; + } + } +} \ No newline at end of file diff --git a/TextCreator/TextCreator.csproj b/TextCreator/TextCreator.csproj index 6275c2b40..0b38c10db 100644 --- a/TextCreator/TextCreator.csproj +++ b/TextCreator/TextCreator.csproj @@ -129,6 +129,10 @@ false + + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll + True + False ..\Submodules\agg-sharp\PlatformWin32\OpenTK.dll @@ -136,9 +140,14 @@ - - - + + + + + + + + @@ -149,6 +158,10 @@ {9B062971-A88E-4A3D-B3C9-12B78D15FA66} clipper_library + + {7E61A5BD-E78F-4B80-88C9-3821B4FA062E} + Csg + {94838988-523C-4B11-AD82-8B9B76F23A31} DataConverters2D @@ -212,6 +225,9 @@ + + + diff --git a/TextCreator/View3DTextCreator.cs b/TextCreator/View3DTextCreator.cs deleted file mode 100644 index 21645e044..000000000 --- a/TextCreator/View3DTextCreator.cs +++ /dev/null @@ -1,958 +0,0 @@ -/* -Copyright (c) 2014, Lars Brubaker -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 MatterHackers.Agg; -using MatterHackers.Agg.Font; -using MatterHackers.Agg.ImageProcessing; -using MatterHackers.Agg.PlatformAbstract; -using MatterHackers.Agg.UI; -using MatterHackers.DataConverters3D; -using MatterHackers.Localizations; -using MatterHackers.MatterControl.DataStorage; -using MatterHackers.MatterControl.PartPreviewWindow; -using MatterHackers.MatterControl.PrintLibrary; -using MatterHackers.MatterControl.PrintQueue; -using MatterHackers.MatterControl.SlicerConfiguration; -using MatterHackers.MeshVisualizer; -using MatterHackers.PolygonMesh; -using MatterHackers.PolygonMesh.Csg; -using MatterHackers.PolygonMesh.Processors; -using MatterHackers.RayTracer; -using MatterHackers.RayTracer.Traceable; -using MatterHackers.RenderOpenGl; -using MatterHackers.VectorMath; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace MatterHackers.MatterControl.Plugins.TextCreator -{ - public class View3DTextCreator : PartPreview3DWidget - { - MHTextEditWidget textToAddWidget; - private SolidSlider spacingScrollBar; - private SolidSlider sizeScrollBar; - private SolidSlider heightScrollBar; - - private CheckBox createUnderline; - - private double lastHeightValue = 1; - private double lastSizeValue = 1; - - private ProgressControl processingProgressControl; - private FlowLayoutWidget editPlateButtonsContainer; - - private Button saveButton; - private Button saveAndExitButton; - private Button closeButton; - private String word; - - private List asyncMeshGroups = new List(); - private List asyncMeshGroupTransforms = new List(); - private List asyncPlatingDatas = new List(); - - private List MeshGroupExtraData; - - public Matrix4X4 SelectedMeshTransform - { - get { return meshViewerWidget.SelectedMeshGroupTransform; } - set { meshViewerWidget.SelectedMeshGroupTransform = value; } - } - - public MeshGroup SelectedMeshGroup - { - get - { - return meshViewerWidget.SelectedMeshGroup; - } - } - - public int SelectedMeshGroupIndex - { - get - { - return meshViewerWidget.SelectedMeshGroupIndex; - } - set - { - meshViewerWidget.SelectedMeshGroupIndex = value; - } - } - - public List MeshGroups - { - get - { - return meshViewerWidget.MeshGroups; - } - } - - public List MeshGroupTransforms - { - get { return meshViewerWidget.MeshGroupTransforms; } - } - - internal struct MeshSelectInfo - { - internal bool downOnPart; - internal PlaneShape hitPlane; - internal Vector3 planeDownHitPos; - internal Vector3 lastMoveDelta; - } - - private TypeFace boldTypeFace; - - public View3DTextCreator(Vector3 viewerVolume, Vector2 bedCenter, BedShape bedShape) - { - boldTypeFace = TypeFace.LoadFrom(StaticData.Instance.ReadAllText(Path.Combine("Fonts", "LiberationSans-Bold.svg"))); - - MeshGroupExtraData = new List(); - - FlowLayoutWidget mainContainerTopToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom); - mainContainerTopToBottom.HAnchor = Agg.UI.HAnchor.Max_FitToChildren_ParentWidth; - mainContainerTopToBottom.VAnchor = Agg.UI.VAnchor.Max_FitToChildren_ParentHeight; - - FlowLayoutWidget centerPartPreviewAndControls = new FlowLayoutWidget(FlowDirection.LeftToRight); - centerPartPreviewAndControls.AnchorAll(); - - GuiWidget viewArea = new GuiWidget(); - viewArea.AnchorAll(); - { - meshViewerWidget = new MeshViewerWidget(viewerVolume, bedCenter, bedShape); - meshViewerWidget.AllowBedRenderingWhenEmpty = true; - meshViewerWidget.AnchorAll(); - } - viewArea.AddChild(meshViewerWidget); - - centerPartPreviewAndControls.AddChild(viewArea); - mainContainerTopToBottom.AddChild(centerPartPreviewAndControls); - - FlowLayoutWidget buttonBottomPanel = new FlowLayoutWidget(FlowDirection.LeftToRight); - buttonBottomPanel.HAnchor = HAnchor.ParentLeftRight; - buttonBottomPanel.Padding = new BorderDouble(3, 3); - buttonBottomPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - - buttonRightPanel = CreateRightButtonPanel(viewerVolume.y); - - // add in the plater tools - { - FlowLayoutWidget editToolBar = new FlowLayoutWidget(); - - processingProgressControl = new ProgressControl("Finding Parts:".Localize(), ActiveTheme.Instance.PrimaryTextColor, ActiveTheme.Instance.PrimaryAccentColor); - processingProgressControl.VAnchor = Agg.UI.VAnchor.ParentCenter; - editToolBar.AddChild(processingProgressControl); - editToolBar.VAnchor |= Agg.UI.VAnchor.ParentCenter; - - editPlateButtonsContainer = new FlowLayoutWidget(); - - textToAddWidget = new MHTextEditWidget("", pixelWidth: 300, messageWhenEmptyAndNotSelected: "Enter Text Here".Localize()); - textToAddWidget.VAnchor = VAnchor.ParentCenter; - textToAddWidget.Margin = new BorderDouble(5); - editPlateButtonsContainer.AddChild(textToAddWidget); - textToAddWidget.ActualTextEditWidget.EnterPressed += (object sender, KeyEventArgs keyEvent) => - { - InsertTextNow(textToAddWidget.Text); - }; - - Button insertTextButton = textImageButtonFactory.Generate("Insert".Localize()); - editPlateButtonsContainer.AddChild(insertTextButton); - insertTextButton.Click += (sender, e) => - { - InsertTextNow(textToAddWidget.Text); - }; - - KeyDown += (sender, e) => - { - KeyEventArgs keyEvent = e as KeyEventArgs; - if (keyEvent != null && !keyEvent.Handled) - { - if (keyEvent.KeyCode == Keys.Escape) - { - if (meshSelectInfo.downOnPart) - { - meshSelectInfo.downOnPart = false; - - SelectedMeshTransform *= transformOnMouseDown; - - Invalidate(); - } - } - } - }; - - editToolBar.AddChild(editPlateButtonsContainer); - buttonBottomPanel.AddChild(editToolBar); - } - - GuiWidget buttonRightPanelHolder = new GuiWidget() - { - HAnchor = HAnchor.FitToChildren, - VAnchor = VAnchor.ParentBottomTop - }; - centerPartPreviewAndControls.AddChild(buttonRightPanelHolder); - buttonRightPanelHolder.AddChild(buttonRightPanel); - - viewControls3D = new ViewControls3D(meshViewerWidget); - - viewControls3D.ResetView += (sender, e) => - { - meshViewerWidget.ResetView(); - }; - - buttonRightPanelDisabledCover = new GuiWidget() - { - HAnchor = HAnchor.ParentLeftRight, - VAnchor = VAnchor.ParentBottomTop - }; - buttonRightPanelDisabledCover.BackgroundColor = new RGBA_Bytes(ActiveTheme.Instance.PrimaryBackgroundColor, 150); - buttonRightPanelHolder.AddChild(buttonRightPanelDisabledCover); - LockEditControls(); - - GuiWidget leftRightSpacer = new GuiWidget(); - leftRightSpacer.HAnchor = HAnchor.ParentLeftRight; - buttonBottomPanel.AddChild(leftRightSpacer); - - closeButton = textImageButtonFactory.Generate("Close".Localize()); - buttonBottomPanel.AddChild(closeButton); - - mainContainerTopToBottom.AddChild(buttonBottomPanel); - - this.AddChild(mainContainerTopToBottom); - this.AnchorAll(); - - meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation; - - AddChild(viewControls3D); - - meshViewerWidget.ResetView(); - - AddHandlers(); - UnlockEditControls(); - // but make sure we can't use the right panel yet - buttonRightPanelDisabledCover.Visible = true; - } - - private async void InsertTextNow(string text) - { - if (text.Length > 0) - { - this.word = text; - ResetWordLayoutSettings(); - processingProgressControl.ProcessType = "Inserting Text".Localize(); - processingProgressControl.Visible = true; - processingProgressControl.PercentComplete = 0; - LockEditControls(); - - await Task.Run(() => insertTextBackgroundWorker_DoWork(text)); - - UnlockEditControls(); - PullMeshDataFromAsynchLists(); - saveButton.Visible = true; - saveAndExitButton.Visible = true; - // now set the selection to the new copy - SelectedMeshGroupIndex = 0; - } - - meshViewerWidget.ResetView(); - } - - private void ResetWordLayoutSettings() - { - spacingScrollBar.Value = 1; - sizeScrollBar.Value = 1; - heightScrollBar.Value = .25; - lastHeightValue = 1; - lastSizeValue = 1; - } - - private bool FindMeshGroupHitPosition(Vector2 screenPosition, out int meshHitIndex) - { - meshHitIndex = 0; - if (MeshGroupExtraData.Count == 0 || MeshGroupExtraData[0].meshTraceableData == null) - { - return false; - } - - List mesheTraceables = new List(); - for (int i = 0; i < MeshGroupExtraData.Count; i++) - { - foreach (IPrimitive traceData in MeshGroupExtraData[i].meshTraceableData) - { - mesheTraceables.Add(new Transform(traceData, MeshGroupTransforms[i])); - } - } - IPrimitive allObjects = BoundingVolumeHierarchy.CreateNewHierachy(mesheTraceables); - - Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, screenPosition); - Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayFromScreen(meshViewerWidgetScreenPosition); - IntersectInfo info = allObjects.GetClosestIntersection(ray); - if (info != null) - { - meshSelectInfo.planeDownHitPos = info.hitPosition; - meshSelectInfo.lastMoveDelta = new Vector3(); - - for (int i = 0; i < MeshGroupExtraData.Count; i++) - { - List insideBounds = new List(); - foreach (IPrimitive traceData in MeshGroupExtraData[i].meshTraceableData) - { - traceData.GetContained(insideBounds, info.closestHitObject.GetAxisAlignedBoundingBox()); - } - if (insideBounds.Contains(info.closestHitObject)) - { - meshHitIndex = i; - return true; - } - } - } - - return false; - } - - private Matrix4X4 transformOnMouseDown = Matrix4X4.Identity; - private MeshSelectInfo meshSelectInfo; - - public override void OnMouseDown(MouseEventArgs mouseEvent) - { - base.OnMouseDown(mouseEvent); - if (meshViewerWidget.TrackballTumbleWidget.UnderMouseState == Agg.UI.UnderMouseState.FirstUnderMouse) - { - if (meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None) - { - viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect; - int meshHitIndex; - if (FindMeshGroupHitPosition(mouseEvent.Position, out meshHitIndex)) - { - meshSelectInfo.hitPlane = new PlaneShape(Vector3.UnitZ, meshSelectInfo.planeDownHitPos.z, null); - SelectedMeshGroupIndex = meshHitIndex; - transformOnMouseDown = SelectedMeshTransform; - Invalidate(); - meshSelectInfo.downOnPart = true; - } - } - } - } - - private bool firstDraw = true; - - public override void OnDraw(Graphics2D graphics2D) - { - if (firstDraw) - { - if (!UserSettings.Instance.IsTouchScreen) - { - textToAddWidget.Focus(); - } - - //textToAddWidget.Text = "Test Text"; - firstDraw = false; - } - //DoCsgTest(); - base.OnDraw(graphics2D); - } - - public override void OnMouseMove(MouseEventArgs mouseEvent) - { - if (meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None && meshSelectInfo.downOnPart) - { - Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, new Vector2(mouseEvent.X, mouseEvent.Y)); - Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayFromScreen(meshViewerWidgetScreenPosition); - IntersectInfo info = meshSelectInfo.hitPlane.GetClosestIntersection(ray); - if (info != null) - { - Vector3 delta = info.hitPosition - meshSelectInfo.planeDownHitPos; - - Matrix4X4 totalTransform = Matrix4X4.CreateTranslation(new Vector3(-meshSelectInfo.lastMoveDelta)); - totalTransform *= Matrix4X4.CreateTranslation(new Vector3(delta)); - meshSelectInfo.lastMoveDelta = delta; - - SelectedMeshTransform *= totalTransform; - - Invalidate(); - } - } - - base.OnMouseMove(mouseEvent); - } - - public override void OnMouseUp(MouseEventArgs mouseEvent) - { - if (meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None - && meshSelectInfo.downOnPart - && meshSelectInfo.lastMoveDelta != Vector3.Zero) - { - saveButton.Visible = true; - saveAndExitButton.Visible = true; - } - - meshSelectInfo.downOnPart = false; - - base.OnMouseUp(mouseEvent); - } - - private void insertTextBackgroundWorker_DoWork(string currentText) - { - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - - asyncMeshGroups.Clear(); - asyncMeshGroupTransforms.Clear(); - asyncPlatingDatas.Clear(); - - TypeFacePrinter printer = new TypeFacePrinter(currentText, new StyledTypeFace(boldTypeFace, 12)); - Vector2 size = printer.GetSize(currentText); - double centerOffset = -size.x / 2; - - double ratioPerMeshGroup = 1.0 / currentText.Length; - double currentRatioDone = 0; - for (int i = 0; i < currentText.Length; i++) - { - int newIndex = asyncMeshGroups.Count; - - TypeFacePrinter letterPrinter = new TypeFacePrinter(currentText[i].ToString(), new StyledTypeFace(boldTypeFace, 12)); - Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, 10 + (i % 2)); - - if (textMesh.Faces.Count > 0) - { - asyncMeshGroups.Add(new MeshGroup(textMesh)); - - PlatingMeshGroupData newMeshInfo = new PlatingMeshGroupData(); - - newMeshInfo.spacing.x = printer.GetOffsetLeftOfCharacterIndex(i).x + centerOffset; - asyncPlatingDatas.Add(newMeshInfo); - asyncMeshGroupTransforms.Add(Matrix4X4.Identity); - - PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, newIndex, (double progress0To1, string processingState, out bool continueProcessing) => - { - continueProcessing = true; - int nextPercent = (int)((currentRatioDone + ratioPerMeshGroup * progress0To1) * 100); - processingProgressControl.PercentComplete = nextPercent; - }); - - currentRatioDone += ratioPerMeshGroup; - - PlatingHelper.PlaceMeshGroupOnBed(asyncMeshGroups, asyncMeshGroupTransforms, newIndex); - } - - processingProgressControl.PercentComplete = ((i + 1) * 95 / currentText.Length); - } - - SetWordSpacing(asyncMeshGroups, asyncMeshGroupTransforms, asyncPlatingDatas); - SetWordSize(asyncMeshGroups, asyncMeshGroupTransforms); - SetWordHeight(asyncMeshGroups, asyncMeshGroupTransforms); - - if (createUnderline.Checked) - { - CreateUnderline(asyncMeshGroups, asyncMeshGroupTransforms, asyncPlatingDatas); - } - - processingProgressControl.PercentComplete = 95; - } - - private void CreateUnderline(List meshesList, List meshTransforms, List platingDataList) - { - if (meshesList.Count > 0) - { - AxisAlignedBoundingBox bounds = meshesList[0].GetAxisAlignedBoundingBox(meshTransforms[0]); - for (int i = 1; i < meshesList.Count; i++) - { - bounds = AxisAlignedBoundingBox.Union(bounds, meshesList[i].GetAxisAlignedBoundingBox(meshTransforms[i])); - } - - double xSize = bounds.XSize; - double ySize = sizeScrollBar.Value * 3; - double zSize = bounds.ZSize / 3; - Mesh connectionLine = PlatonicSolids.CreateCube(xSize, ySize, zSize); - meshesList.Add(new MeshGroup(connectionLine)); - platingDataList.Add(new PlatingMeshGroupData()); - meshTransforms.Add(Matrix4X4.CreateTranslation((bounds.maxXYZ.x + bounds.minXYZ.x) / 2, bounds.minXYZ.y + ySize / 2 - ySize * 1 / 3, zSize / 2)); - PlatingHelper.CreateITraceableForMeshGroup(platingDataList, meshesList, meshesList.Count - 1, null); - } - } - - private void PushMeshGroupDataToAsynchLists(bool copyTraceInfo) - { - asyncMeshGroups.Clear(); - asyncMeshGroupTransforms.Clear(); - for (int meshGroupIndex = 0; meshGroupIndex < MeshGroups.Count; meshGroupIndex++) - { - MeshGroup meshGroup = MeshGroups[meshGroupIndex]; - MeshGroup newMeshGroup = new MeshGroup(); - for (int meshIndex = 0; meshIndex < meshGroup.Meshes.Count; meshIndex++) - { - Mesh mesh = meshGroup.Meshes[meshIndex]; - newMeshGroup.Meshes.Add(Mesh.Copy(mesh)); - asyncMeshGroupTransforms.Add(MeshGroupTransforms[meshGroupIndex]); - } - asyncMeshGroups.Add(newMeshGroup); - } - asyncPlatingDatas.Clear(); - - for (int meshGroupIndex = 0; meshGroupIndex < MeshGroupExtraData.Count; meshGroupIndex++) - { - PlatingMeshGroupData meshData = new PlatingMeshGroupData(); - MeshGroup meshGroup = MeshGroups[meshGroupIndex]; - for (int meshIndex = 0; meshIndex < meshGroup.Meshes.Count; meshIndex++) - { - if (copyTraceInfo) - { - meshData.meshTraceableData.AddRange(MeshGroupExtraData[meshGroupIndex].meshTraceableData); - } - } - asyncPlatingDatas.Add(meshData); - } - } - - private void arrangePartsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - UnlockEditControls(); - saveButton.Visible = true; - saveAndExitButton.Visible = true; - viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect; - - PullMeshDataFromAsynchLists(); - } - - private void PullMeshDataFromAsynchLists() - { - MeshGroups.Clear(); - foreach (MeshGroup mesh in asyncMeshGroups) - { - MeshGroups.Add(mesh); - } - MeshGroupTransforms.Clear(); - foreach (Matrix4X4 transform in asyncMeshGroupTransforms) - { - MeshGroupTransforms.Add(transform); - } - MeshGroupExtraData.Clear(); - foreach (PlatingMeshGroupData meshData in asyncPlatingDatas) - { - MeshGroupExtraData.Add(meshData); - } - } - - private void meshViewerWidget_LoadDone(object sender, EventArgs e) - { - UnlockEditControls(); - } - - private void LockEditControls() - { - editPlateButtonsContainer.Visible = false; - buttonRightPanelDisabledCover.Visible = true; - - viewControls3D.PartSelectVisible = false; - if (meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None) - { - viewControls3D.ActiveButton = ViewControls3DButtons.Rotate; - } - } - - private void UnlockEditControls() - { - buttonRightPanelDisabledCover.Visible = false; - processingProgressControl.Visible = false; - - viewControls3D.PartSelectVisible = true; - editPlateButtonsContainer.Visible = true; - } - - private void DeleteSelectedMesh() - { - // don't ever delete the last mesh - if (MeshGroups.Count > 1) - { - int removeIndex = SelectedMeshGroupIndex; - MeshGroups.RemoveAt(removeIndex); - MeshGroupExtraData.RemoveAt(removeIndex); - MeshGroupTransforms.RemoveAt(removeIndex); - SelectedMeshGroupIndex = Math.Min(SelectedMeshGroupIndex, MeshGroups.Count - 1); - saveButton.Visible = true; - saveAndExitButton.Visible = true; - Invalidate(); - } - } - - private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) - { - processingProgressControl.PercentComplete = e.ProgressPercentage; - } - - private FlowLayoutWidget CreateRightButtonPanel(double buildHeight) - { - FlowLayoutWidget buttonRightPanel = new FlowLayoutWidget(FlowDirection.TopToBottom); - buttonRightPanel.Width = 200; - { - BorderDouble buttonMargin = new BorderDouble(top: 3); - - // put in the word editing menu - { - CheckBox expandWordOptions = ExpandMenuOptionFactory.GenerateCheckBoxButton("Word Edit".Localize(), - View3DWidget.ArrowRight, - View3DWidget.ArrowDown); - expandWordOptions.Margin = new BorderDouble(bottom: 2); - buttonRightPanel.AddChild(expandWordOptions); - - FlowLayoutWidget wordOptionContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); - wordOptionContainer.HAnchor = HAnchor.ParentLeftRight; - wordOptionContainer.Visible = false; - buttonRightPanel.AddChild(wordOptionContainer); - - spacingScrollBar = InsertUiForSlider(wordOptionContainer, "Spacing:".Localize(), .5, 1); - { - spacingScrollBar.ValueChanged += (sender, e) => - { - SetWordSpacing(MeshGroups, MeshGroupTransforms, MeshGroupExtraData); - RebuildUnderlineIfRequired(); - }; - } - - sizeScrollBar = InsertUiForSlider(wordOptionContainer, "Size:".Localize(), .3, 2); - { - sizeScrollBar.ValueChanged += (sender, e) => - { - SetWordSize(MeshGroups, MeshGroupTransforms); - - //SetWordSpacing(MeshGroups, MeshGroupTransforms, MeshGroupExtraData); - RebuildUnderlineIfRequired(); - }; - } - - heightScrollBar = InsertUiForSlider(wordOptionContainer, "Height:".Localize(), .05, 1); - { - heightScrollBar.ValueChanged += (sender, e) => - { - SetWordHeight(MeshGroups, MeshGroupTransforms); - RebuildUnderlineIfRequired(); - }; - } - - createUnderline = new CheckBox(new CheckBoxViewText("Underline".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor)); - createUnderline.Checked = true; - createUnderline.Margin = new BorderDouble(10, 5); - createUnderline.HAnchor = HAnchor.ParentLeft; - wordOptionContainer.AddChild(createUnderline); - createUnderline.CheckedStateChanged += (sender, e) => - { - int oldIndex = SelectedMeshGroupIndex; - if (!createUnderline.Checked) - { - // we need to remove the underline - if (MeshGroups.Count > 1) - { - SelectedMeshGroupIndex = MeshGroups.Count - 1; - DeleteSelectedMesh(); - } - } - else if (MeshGroups.Count > 0) - { - // we need to add the underline - CreateUnderline(MeshGroups, MeshGroupTransforms, MeshGroupExtraData); - } - SelectedMeshGroupIndex = Math.Min(oldIndex, MeshGroups.Count - 1); - }; - - expandWordOptions.CheckedStateChanged += (sender, e) => - { - wordOptionContainer.Visible = expandWordOptions.Checked; - }; - - expandWordOptions.Checked = true; - } - - // put in the letter editing menu - { - CheckBox expandLetterOptions = ExpandMenuOptionFactory.GenerateCheckBoxButton("Letter", - View3DWidget.ArrowRight, - View3DWidget.ArrowDown); - expandLetterOptions.Margin = new BorderDouble(bottom: 2); - //buttonRightPanel.AddChild(expandLetterOptions); - - FlowLayoutWidget letterOptionContainer = new FlowLayoutWidget(FlowDirection.TopToBottom); - letterOptionContainer.HAnchor = HAnchor.ParentLeftRight; - letterOptionContainer.Visible = false; - buttonRightPanel.AddChild(letterOptionContainer); - - SolidSlider sizeScrollBar = InsertUiForSlider(letterOptionContainer, "Size:".Localize()); - SolidSlider heightScrollBar = InsertUiForSlider(letterOptionContainer, "Height:".Localize()); - SolidSlider rotationScrollBar = InsertUiForSlider(letterOptionContainer, "Rotation:".Localize()); - - expandLetterOptions.CheckedStateChanged += (sender, e) => - { - letterOptionContainer.Visible = expandLetterOptions.Checked; - }; - } - - GuiWidget verticalSpacer = new GuiWidget(); - verticalSpacer.VAnchor = VAnchor.ParentBottomTop; - buttonRightPanel.AddChild(verticalSpacer); - - saveButton = WhiteButtonFactory.Generate("Save".Localize(), centerText: true); - saveButton.Visible = false; - saveButton.Cursor = Cursors.Hand; - - saveAndExitButton = WhiteButtonFactory.Generate("Save & Exit".Localize(), centerText: true); - saveAndExitButton.Visible = false; - saveAndExitButton.Cursor = Cursors.Hand; - - //buttonRightPanel.AddChild(saveButton); - buttonRightPanel.AddChild(saveAndExitButton); - } - - buttonRightPanel.Padding = new BorderDouble(6, 6); - buttonRightPanel.Margin = new BorderDouble(0, 1); - buttonRightPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - buttonRightPanel.VAnchor = VAnchor.ParentBottomTop; - - return buttonRightPanel; - } - - private void RebuildUnderlineIfRequired() - { - if (createUnderline.Checked) - { - // we need to remove the underline - if (MeshGroups.Count > 1) - { - int oldIndex = SelectedMeshGroupIndex; - SelectedMeshGroupIndex = MeshGroups.Count - 1; - DeleteSelectedMesh(); - // we need to add the underline - CreateUnderline(MeshGroups, MeshGroupTransforms, MeshGroupExtraData); - SelectedMeshGroupIndex = oldIndex; - } - } - } - - private void SetWordSpacing(List meshesList, List meshTransforms, List platingDataList) - { - if (meshesList.Count > 0) - { - for (int meshIndex = 0; meshIndex < meshesList.Count; meshIndex++) - { - Vector3 startPosition = Vector3.Transform(Vector3.Zero, meshTransforms[meshIndex]); - - meshTransforms[meshIndex] *= Matrix4X4.CreateTranslation(-startPosition); - double newX = platingDataList[meshIndex].spacing.x * spacingScrollBar.Value * lastSizeValue; - meshTransforms[meshIndex] *= Matrix4X4.CreateTranslation(new Vector3(newX, 0, 0) + new Vector3(MeshViewerWidget.BedCenter)); - } - } - } - - private void SetWordSize(List meshesList, List meshTransforms) - { - Vector3 bedCenter = new Vector3(MeshViewerWidget.BedCenter); - if (meshesList.Count > 0) - { - for (int meshIndex = 0; meshIndex < meshesList.Count; meshIndex++) - { - // take out the last scale - double oldSize = 1.0 / lastSizeValue; - - double newSize = sizeScrollBar.Value; - - meshTransforms[meshIndex] = PlatingHelper.ApplyAtPosition(meshTransforms[meshIndex], Matrix4X4.CreateScale(new Vector3(oldSize, oldSize, oldSize)), new Vector3(bedCenter)); - meshTransforms[meshIndex] = PlatingHelper.ApplyAtPosition(meshTransforms[meshIndex], Matrix4X4.CreateScale(new Vector3(newSize, newSize, newSize)), new Vector3(bedCenter)); - } - - lastSizeValue = sizeScrollBar.Value; - } - } - - private void SetWordHeight(List meshesList, List meshTransforms) - { - if (meshesList.Count > 0) - { - for (int meshIndex = 0; meshIndex < meshesList.Count; meshIndex++) - { - // take out the last scale - double oldHeight = lastHeightValue; - meshTransforms[meshIndex] *= Matrix4X4.CreateScale(new Vector3(1, 1, 1 / oldHeight)); - - double newHeight = heightScrollBar.Value; - meshTransforms[meshIndex] *= Matrix4X4.CreateScale(new Vector3(1, 1, newHeight)); - } - - lastHeightValue = heightScrollBar.Value; - } - } - - private void AddLetterControls(FlowLayoutWidget buttonPanel) - { - textImageButtonFactory.FixedWidth = 44 * GuiWidget.DeviceScale; - - FlowLayoutWidget degreesContainer = new FlowLayoutWidget(FlowDirection.LeftToRight); - degreesContainer.HAnchor = HAnchor.ParentLeftRight; - degreesContainer.Padding = new BorderDouble(5); - - GuiWidget horizontalSpacer = new GuiWidget(); - horizontalSpacer.HAnchor = HAnchor.ParentLeftRight; - - TextWidget degreesLabel = new TextWidget("Degrees:".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor); - degreesContainer.AddChild(degreesLabel); - degreesContainer.AddChild(horizontalSpacer); - - MHNumberEdit degreesControl = new MHNumberEdit(45, pixelWidth: 40, allowNegatives: true, increment: 5, minValue: -360, maxValue: 360); - degreesControl.VAnchor = Agg.UI.VAnchor.ParentTop; - degreesContainer.AddChild(degreesControl); - - buttonPanel.AddChild(degreesContainer); - - FlowLayoutWidget rotateButtonContainer = new FlowLayoutWidget(FlowDirection.LeftToRight); - rotateButtonContainer.HAnchor = HAnchor.ParentLeftRight; - - buttonPanel.AddChild(rotateButtonContainer); - - buttonPanel.AddChild(generateHorizontalRule()); - textImageButtonFactory.FixedWidth = 0; - } - - private GuiWidget generateHorizontalRule() - { - GuiWidget horizontalRule = new GuiWidget(); - horizontalRule.Height = 1; - horizontalRule.Margin = new BorderDouble(0, 1, 0, 3); - horizontalRule.HAnchor = HAnchor.ParentLeftRight; - horizontalRule.BackgroundColor = new RGBA_Bytes(255, 255, 255, 200); - return horizontalRule; - } - - private void AddHandlers() - { - closeButton.Click += onCloseButton_Click; - - saveButton.Click += (sender, e) => - { - MergeAndSavePartsToStl(); - }; - - saveAndExitButton.Click += (sender, e) => - { - MergeAndSavePartsToStl(); - }; - } - - private bool partSelectButtonWasClicked = false; - - private async void MergeAndSavePartsToStl() - { - if (MeshGroups.Count > 0) - { - partSelectButtonWasClicked = viewControls3D.ActiveButton == ViewControls3DButtons.PartSelect; - - - processingProgressControl.ProcessType = "Saving Parts:".Localize(); - processingProgressControl.Visible = true; - processingProgressControl.PercentComplete = 0; - LockEditControls(); - - // we sent the data to the async lists but we will not pull it back out (only use it as a temp holder). - PushMeshGroupDataToAsynchLists(true); - - string fileName = "TextCreator_{0}".FormatWith(Path.ChangeExtension(Path.GetRandomFileName(), ".amf")); - string filePath = Path.Combine(ApplicationDataStorage.Instance.ApplicationLibraryDataPath, fileName); - - processingProgressControl.RatioComplete = 0; - await Task.Run(() => mergeAndSavePartsBackgroundWorker_DoWork(filePath)); - - PrintItem printItem = new PrintItem(); - - printItem.Name = string.Format("{0}", word); - printItem.FileLocation = Path.GetFullPath(filePath); - - PrintItemWrapper printItemWrapper = new PrintItemWrapper(printItem); - - // and save to the queue - QueueData.Instance.AddItem(printItemWrapper); - - //Exit after save - UiThread.RunOnIdle(CloseOnIdle); - } - } - - private void mergeAndSavePartsBackgroundWorker_DoWork(string filePath) - { - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - try - { - // push all the transforms into the meshes - for (int i = 0; i < asyncMeshGroups.Count; i++) - { - asyncMeshGroups[i].Transform(MeshGroupTransforms[i]); - - processingProgressControl.RatioComplete = (double)i / asyncMeshGroups.Count * .1; - } - - List mergResults = new List(); - mergResults.Add(new MeshGroup()); - mergResults[0].Meshes.Add(new Mesh()); - double meshGroupIndex = 0; - foreach (MeshGroup meshGroup in asyncMeshGroups) - { - foreach (Mesh mesh in meshGroup.Meshes) - { - processingProgressControl.RatioComplete = .1 + (double)meshGroupIndex / asyncMeshGroups.Count; - mergResults[0].Meshes[0] = CsgOperations.Union(mergResults[0].Meshes[0], mesh); - } - meshGroupIndex++; - } - - MeshFileIo.Save(mergResults, filePath); - } - catch (System.UnauthorizedAccessException) - { - //Do something special when unauthorized? - UiThread.RunOnIdle(() => StyledMessageBox.ShowMessageBox(null, "Oops! Unable to save changes.".Localize(), "Unable to save".Localize())); - } - catch - { - UiThread.RunOnIdle(() => StyledMessageBox.ShowMessageBox(null, "Oops! Unable to save changes.".Localize(), "Unable to save".Localize())); - } - } - - private bool scaleQueueMenu_Click() - { - return true; - } - - private bool rotateQueueMenu_Click() - { - return true; - } - - private void onCloseButton_Click(object sender, EventArgs e) - { - UiThread.RunOnIdle(Close); - } - } -} \ No newline at end of file diff --git a/Utilities/ProjectFileHandler.cs b/Utilities/ProjectFileHandler.cs index a3c2a68b0..09f53ad4b 100644 --- a/Utilities/ProjectFileHandler.cs +++ b/Utilities/ProjectFileHandler.cs @@ -28,6 +28,7 @@ either expressed or implied, of the FreeBSD Project. */ using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.PolygonMesh.Processors; @@ -240,7 +241,7 @@ namespace MatterHackers.MatterControl } } - public List ImportFromProjectArchive(string loadedFileName = null) + public static List ImportFromProjectArchive(string loadedFileName = null) { if (loadedFileName == null) { @@ -320,7 +321,11 @@ namespace MatterHackers.MatterControl { for (int i = 1; i <= item.ItemQuantity; i++) { - printItemList.Add(this.GetPrintItemFromFile(Path.Combine(stagingFolder, item.FileName), item.Name)); + printItemList.Add(new PrintItem() + { + FileLocation = Path.Combine(stagingFolder, item.FileName), + Name = item.Name + }); } } } @@ -329,7 +334,11 @@ namespace MatterHackers.MatterControl string[] files = Directory.GetFiles(stagingFolder, "*.*", SearchOption.AllDirectories); foreach (string fileName in files) { - printItemList.Add(this.GetPrintItemFromFile(fileName, Path.GetFileNameWithoutExtension(fileName))); + printItemList.Add(new PrintItem() + { + FileLocation = fileName, + Name = Path.GetFileNameWithoutExtension(fileName) + }); } } @@ -341,13 +350,5 @@ namespace MatterHackers.MatterControl return null; } } - - private PrintItem GetPrintItemFromFile(string fileName, string displayName) - { - PrintItem item = new PrintItem(); - item.FileLocation = fileName; - item.Name = displayName; - return item; - } } } \ No newline at end of file