mattercontrol/PartPreviewWindow/View3D/View3DWidget.cs

2424 lines
75 KiB
C#
Raw Normal View History

2014-01-29 19:09:30 -08:00
/*
Copyright (c) 2014, Lars Brubaker
2014-01-29 19:09:30 -08:00
All rights reserved.
Redistribution and use in source and binary forms, with or without
2015-04-08 15:20:10 -07:00
modification, are permitted provided that the following conditions are met:
2014-01-29 19:09:30 -08:00
1. Redistributions of source code must retain the above copyright notice, this
2015-04-08 15:20:10 -07:00
list of conditions and the following disclaimer.
2014-01-29 19:09:30 -08:00
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
2015-04-08 15:20:10 -07:00
and/or other materials provided with the distribution.
2014-01-29 19:09:30 -08:00
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
2015-04-08 15:20:10 -07:00
of the authors and should not be interpreted as representing official policies,
2014-01-29 19:09:30 -08:00
either expressed or implied, of the FreeBSD Project.
*/
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.ImageProcessing;
using MatterHackers.Agg.PlatformAbstract;
2015-04-08 15:20:10 -07:00
using MatterHackers.Agg.Transform;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
2017-03-15 16:17:06 -07:00
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.DataStorage;
using MatterHackers.MatterControl.PrinterCommunication;
using MatterHackers.MatterControl.PrintLibrary.Provider;
using MatterHackers.MatterControl.PrintQueue;
using MatterHackers.MatterControl.SlicerConfiguration;
2014-01-29 19:09:30 -08:00
using MatterHackers.MeshVisualizer;
using MatterHackers.PolygonMesh;
2014-01-29 19:09:30 -08:00
using MatterHackers.PolygonMesh.Processors;
using MatterHackers.RayTracer;
using MatterHackers.RayTracer.Traceable;
using MatterHackers.RenderOpenGl;
using MatterHackers.VectorMath;
2017-03-15 16:17:06 -07:00
using Newtonsoft.Json;
2015-04-08 15:20:10 -07:00
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
2015-04-08 15:20:10 -07:00
using System.Threading;
using System.Threading.Tasks;
2017-03-15 16:17:06 -07:00
using System.Xml.Linq;
2014-01-29 19:09:30 -08:00
namespace MatterHackers.MatterControl.PartPreviewWindow
{
2017-03-15 16:17:06 -07:00
public class BaseObject3DEditor : IObject3DEditor
{
private IObject3D item;
private View3DWidget view3DWidget;
public string Name { get { return "General"; } }
public IEnumerable<Type> 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
{
2016-03-04 10:11:05 -08:00
InteractionVolume CreateInteractionVolume(View3DWidget widget);
}
2017-03-15 16:17:06 -07:00
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
{
2016-03-04 10:11:05 -08:00
public virtual InteractionVolume CreateInteractionVolume(View3DWidget widget)
{
return null;
}
}
public interface ISideBarToolCreator
{
GuiWidget CreateSideBarTool(View3DWidget widget);
2017-03-15 16:17:06 -07:00
}
2016-03-04 10:11:05 -08:00
public class SideBarPlugin : ISideBarToolCreator
{
public virtual GuiWidget CreateSideBarTool(View3DWidget widget)
{
return null;
}
}
2015-04-08 15:20:10 -07:00
public partial class View3DWidget : PartPreview3DWidget
{
2017-03-15 16:17:06 -07:00
private bool DoBooleanTest = false;
public FlowLayoutWidget doEdittingButtonsContainer;
public UndoBuffer UndoBuffer { get; private set; } = new UndoBuffer();
public readonly int EditButtonHeight = 44;
2017-03-15 16:17:06 -07:00
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;
2015-05-30 12:48:16 -07:00
private bool editorThatRequestedSave = false;
private FlowLayoutWidget enterEditButtonsContainer;
private ExportPrintItemWindow exportingWindow = null;
private ObservableCollection<GuiWidget> extruderButtons = new ObservableCollection<GuiWidget>();
private bool hasDrawn = false;
2017-03-15 16:17:06 -07:00
2015-05-30 12:48:16 -07:00
private OpenMode openMode;
private bool partHasBeenEdited = false;
2017-03-15 16:17:06 -07:00
private PrintItemWrapper printItemWrapper { get; set; }
2015-04-08 15:20:10 -07:00
private ProgressControl processingProgressControl;
2015-05-30 12:48:16 -07:00
private SaveAsWindow saveAsWindow = null;
private SplitButton saveButtons;
private bool saveSucceded = true;
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();
private Matrix4X4 transformOnMouseDown = Matrix4X4.Identity;
private EventHandler unregisterEvents;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
private bool viewIsInEditModePreLock = false;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
private bool wasInSelectMode = false;
2015-04-08 15:20:10 -07:00
public event EventHandler SelectedTransformChanged;
2017-03-15 16:17:06 -07:00
public View3DWidgetSidebar Sidebar;
public static ImageBuffer ArrowRight
{
get
{
2016-10-10 15:16:26 -07:00
if (ActiveTheme.Instance.IsDarkTheme)
{
return StaticData.Instance.LoadIcon("icon_arrow_right_no_border_32x32.png", 32, 32).InvertLightness();
}
else
{
return StaticData.Instance.LoadIcon("icon_arrow_right_no_border_32x32.png", 32, 32);
}
}
}
public static ImageBuffer ArrowDown
{
get
{
2016-10-10 15:16:26 -07:00
if (ActiveTheme.Instance.IsDarkTheme)
{
return StaticData.Instance.LoadIcon("icon_arrow_down_no_border_32x32.png", 32, 32).InvertLightness();
}
else
{
return StaticData.Instance.LoadIcon("icon_arrow_down_no_border_32x32.png", 32, 32);
}
}
}
2017-03-15 16:17:06 -07:00
protected FlowLayoutWidget editPlateButtonsContainer;
public View3DWidget(PrintItemWrapper printItemWrapper, Vector3 viewerVolume, Vector2 bedCenter, BedShape bedShape, WindowMode windowType, AutoRotate autoRotate, OpenMode openMode = OpenMode.Viewing)
2015-05-30 12:48:16 -07:00
{
this.openMode = openMode;
this.windowType = windowType;
allowAutoRotate = (autoRotate == AutoRotate.Enabled);
autoRotating = allowAutoRotate;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
this.printItemWrapper = printItemWrapper;
this.Name = "View3DWidget";
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
FlowLayoutWidget mainContainerTopToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom);
mainContainerTopToBottom.HAnchor = Agg.UI.HAnchor.Max_FitToChildren_ParentWidth;
mainContainerTopToBottom.VAnchor = Agg.UI.VAnchor.Max_FitToChildren_ParentHeight;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
FlowLayoutWidget centerPartPreviewAndControls = new FlowLayoutWidget(FlowDirection.LeftToRight);
centerPartPreviewAndControls.Name = "centerPartPreviewAndControls";
centerPartPreviewAndControls.AnchorAll();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
GuiWidget viewArea = new GuiWidget();
viewArea.AnchorAll();
{
2017-03-15 16:17:06 -07:00
meshViewerWidget = new MeshViewerWidget(viewerVolume, bedCenter, bedShape);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
PutOemImageOnBed();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
meshViewerWidget.AnchorAll();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
viewArea.AddChild(meshViewerWidget);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
centerPartPreviewAndControls.AddChild(viewArea);
mainContainerTopToBottom.AddChild(centerPartPreviewAndControls);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
FlowLayoutWidget buttonBottomPanel = new FlowLayoutWidget(FlowDirection.LeftToRight);
buttonBottomPanel.HAnchor = HAnchor.ParentLeftRight;
buttonBottomPanel.Padding = new BorderDouble(3, 3);
buttonBottomPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor;
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
Sidebar = new View3DWidgetSidebar(this, viewerVolume.y, UndoBuffer);
Sidebar.Name = "buttonRightPanel";
Sidebar.Visible = false;
Sidebar.InitializeComponents();
Scene.SelectionChanged += Scene_SelectionChanged;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
CreateOptionsContent();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
// add in the plater tools
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
FlowLayoutWidget editToolBar = new FlowLayoutWidget();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
string progressFindPartsLabel = "Entering Editor".Localize();
string progressFindPartsLabelFull = "{0}:".FormatWith(progressFindPartsLabel);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
processingProgressControl = new ProgressControl(progressFindPartsLabelFull, ActiveTheme.Instance.PrimaryTextColor, ActiveTheme.Instance.PrimaryAccentColor);
processingProgressControl.VAnchor = Agg.UI.VAnchor.ParentCenter;
editToolBar.AddChild(processingProgressControl);
editToolBar.VAnchor |= Agg.UI.VAnchor.ParentCenter;
processingProgressControl.Visible = false;
2015-04-08 15:20:10 -07:00
// If the window is embedded (in the center panel) and there is no item loaded then don't show the add button
2015-05-30 12:48:16 -07:00
enterEditButtonsContainer = new FlowLayoutWidget();
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
Button addButton = textImageButtonFactory.Generate("Insert".Localize(), "icon_insert_32x32.png");
2015-08-10 13:36:31 -07:00
addButton.ToolTipText = "Insert an .stl, .amf or .zip file".Localize();
2015-05-30 12:48:16 -07:00
addButton.Margin = new BorderDouble(right: 0);
enterEditButtonsContainer.AddChild(addButton);
addButton.Click += (sender, e) =>
2015-04-08 15:20:10 -07:00
{
UiThread.RunOnIdle(() =>
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
SwitchStateToEditing();
2015-05-30 12:48:16 -07:00
});
};
if (printItemWrapper != null
&& printItemWrapper.PrintItem.ReadOnly)
{
addButton.Enabled = false;
}
2015-04-08 15:20:10 -07:00
2016-05-13 11:37:22 -07:00
ImageBuffer normalImage = StaticData.Instance.LoadIcon("icon_edit.png", 14, 14);
Button enterEdittingButton = textImageButtonFactory.Generate("Edit".Localize(), normalImage);
2015-09-01 16:03:29 -07:00
enterEdittingButton.Name = "3D View Edit";
2015-05-30 12:48:16 -07:00
enterEdittingButton.Margin = new BorderDouble(right: 4);
enterEdittingButton.Click += (sender, e) =>
{
2017-03-15 16:17:06 -07:00
SwitchStateToEditing();
2015-05-30 12:48:16 -07:00
};
if (printItemWrapper != null
&& printItemWrapper.PrintItem.ReadOnly)
{
enterEdittingButton.Enabled = false;
}
Button exportButton = textImageButtonFactory.Generate("Export".Localize() + "...");
exportButton.Margin = new BorderDouble(right: 10);
2015-04-08 15:20:10 -07:00
exportButton.Click += (sender, e) =>
{
UiThread.RunOnIdle(() =>
{
OpenExportWindow();
});
};
2015-04-08 15:20:10 -07:00
enterEditButtonsContainer.AddChild(enterEdittingButton);
enterEditButtonsContainer.AddChild(exportButton);
2015-04-08 15:20:10 -07:00
}
editToolBar.AddChild(enterEditButtonsContainer);
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer = new FlowLayoutWidget();
doEdittingButtonsContainer.Visible = false;
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
{
2014-12-20 09:07:13 -08:00
Button addButton = textImageButtonFactory.Generate("Insert".Localize(), "icon_insert_32x32.png");
2015-04-08 15:20:10 -07:00
addButton.Margin = new BorderDouble(right: 10);
doEdittingButtonsContainer.AddChild(addButton);
addButton.Click += (sender, e) =>
{
UiThread.RunOnIdle(() =>
2015-04-08 15:20:10 -07:00
{
FileDialog.OpenFileDialog(
new OpenFileDialogParams(ApplicationSettings.OpenDesignFileParams, multiSelect: true),
(openParams) =>
{
LoadAndAddPartsToPlate(openParams.FileNames);
});
});
};
2014-01-29 19:09:30 -08:00
2014-12-20 09:07:13 -08:00
GuiWidget separator = new GuiWidget(1, 2);
separator.BackgroundColor = ActiveTheme.Instance.PrimaryTextColor;
separator.Margin = new BorderDouble(4, 2);
separator.VAnchor = VAnchor.ParentBottomTop;
doEdittingButtonsContainer.AddChild(separator);
2015-04-08 15:20:10 -07:00
Button ungroupButton = textImageButtonFactory.Generate("Ungroup".Localize());
ungroupButton.Name = "3D View Ungroup";
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer.AddChild(ungroupButton);
ungroupButton.Click += (sender, e) =>
{
UngroupSelectedMeshGroup();
};
2015-04-08 15:20:10 -07:00
Button groupButton = textImageButtonFactory.Generate("Group".Localize());
groupButton.Name = "3D View Group";
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer.AddChild(groupButton);
groupButton.Click += (sender, e) =>
{
GroupSelectedMeshs();
};
2015-04-08 15:20:10 -07:00
Button alignButton = textImageButtonFactory.Generate("Align".Localize());
doEdittingButtonsContainer.AddChild(alignButton);
alignButton.Click += (sender, e) =>
{
AlignToSelectedMeshGroup();
};
Button arrangeButton = textImageButtonFactory.Generate("Arrange".Localize());
doEdittingButtonsContainer.AddChild(arrangeButton);
arrangeButton.Click += (sender, e) =>
{
AutoArrangePartsInBackground();
};
2014-12-20 09:07:13 -08:00
GuiWidget separatorTwo = new GuiWidget(1, 2);
separatorTwo.BackgroundColor = ActiveTheme.Instance.PrimaryTextColor;
separatorTwo.Margin = new BorderDouble(4, 2);
separatorTwo.VAnchor = VAnchor.ParentBottomTop;
doEdittingButtonsContainer.AddChild(separatorTwo);
2015-04-08 15:20:10 -07:00
Button copyButton = textImageButtonFactory.Generate("Copy".Localize());
2015-09-01 16:03:29 -07:00
copyButton.Name = "3D View Copy";
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer.AddChild(copyButton);
copyButton.Click += (sender, e) =>
{
MakeCopyOfGroup();
};
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
Button deleteButton = textImageButtonFactory.Generate("Remove".Localize());
deleteButton.Name = "3D View Remove";
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer.AddChild(deleteButton);
deleteButton.Click += (sender, e) =>
{
DeleteSelectedMesh();
};
2014-12-20 09:07:13 -08:00
GuiWidget separatorThree = new GuiWidget(1, 2);
separatorThree.BackgroundColor = ActiveTheme.Instance.PrimaryTextColor;
separatorThree.Margin = new BorderDouble(4, 1);
separatorThree.VAnchor = VAnchor.ParentBottomTop;
doEdittingButtonsContainer.AddChild(separatorThree);
2016-02-14 17:53:44 -08:00
Button cancelEditModeButton = textImageButtonFactory.Generate("Cancel".Localize(), centerText: true);
cancelEditModeButton.Name = "3D View Cancel";
2016-02-14 17:53:44 -08:00
cancelEditModeButton.Click += (sender, e) =>
{
UiThread.RunOnIdle(() =>
2014-12-20 09:07:13 -08:00
{
if (saveButtons.Visible)
{
2017-03-15 16:17:06 -07:00
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)
2014-12-20 09:07:13 -08:00
{
2017-03-15 16:17:06 -07:00
ExitEditingAndSaveIfRequested(false);
}
else
{
SwitchStateToNotEditing();
}
}
});
};
2016-02-14 17:53:44 -08:00
doEdittingButtonsContainer.AddChild(cancelEditModeButton);
2014-12-20 09:07:13 -08:00
// put in the save button
AddSaveAndSaveAs(doEdittingButtonsContainer);
2015-04-08 15:20:10 -07:00
}
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
editToolBar.AddChild(doEdittingButtonsContainer);
buttonBottomPanel.AddChild(editToolBar);
}
2014-01-29 19:09:30 -08:00
GuiWidget buttonRightPanelHolder = new GuiWidget()
{
HAnchor = HAnchor.FitToChildren,
VAnchor = VAnchor.ParentBottomTop
};
buttonRightPanelHolder.Name = "buttonRightPanelHolder";
2015-04-08 15:20:10 -07:00
centerPartPreviewAndControls.AddChild(buttonRightPanelHolder);
2017-03-15 16:17:06 -07:00
buttonRightPanelHolder.AddChild(Sidebar);
Sidebar.VisibleChanged += (sender, e) =>
{
2017-03-15 16:17:06 -07:00
buttonRightPanelHolder.Visible = Sidebar.Visible;
};
2015-04-08 15:20:10 -07:00
viewControls3D = new ViewControls3D(meshViewerWidget);
viewControls3D.ResetView += (sender, e) =>
{
2016-02-29 14:04:52 -08:00
meshViewerWidget.ResetView();
};
buttonRightPanelDisabledCover = new GuiWidget()
{
HAnchor = HAnchor.ParentLeftRight,
VAnchor = VAnchor.ParentBottomTop
};
2015-04-08 15:20:10 -07:00
buttonRightPanelDisabledCover.BackgroundColor = new RGBA_Bytes(ActiveTheme.Instance.PrimaryBackgroundColor, 150);
buttonRightPanelHolder.AddChild(buttonRightPanelDisabledCover);
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
viewControls3D.PartSelectVisible = false;
LockEditControls();
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
GuiWidget leftRightSpacer = new GuiWidget();
leftRightSpacer.HAnchor = HAnchor.ParentLeftRight;
buttonBottomPanel.AddChild(leftRightSpacer);
2015-04-08 15:20:10 -07:00
if (windowType == WindowMode.StandAlone)
{
Button closeButton = textImageButtonFactory.Generate("Close".Localize());
buttonBottomPanel.AddChild(closeButton);
closeButton.Click += (sender, e) =>
{
CloseOnIdle();
};
}
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
mainContainerTopToBottom.AddChild(buttonBottomPanel);
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
this.AddChild(mainContainerTopToBottom);
this.AnchorAll();
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation;
AddChild(viewControls3D);
2017-03-15 16:17:06 -07:00
/* 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);
2015-04-08 15:20:10 -07:00
UiThread.RunOnIdle(AutoSpin);
2014-05-27 09:16:35 -07:00
2015-04-08 15:20:10 -07:00
if (printItemWrapper == null && windowType == WindowMode.Embeded)
{
enterEditButtonsContainer.Visible = false;
}
if (windowType == WindowMode.Embeded)
{
PrinterConnectionAndCommunication.Instance.CommunicationStateChanged.RegisterEvent(SetEditControlsBasedOnPrinterState, ref unregisterEvents);
if (windowType == WindowMode.Embeded)
{
// make sure we lock the controls if we are printing or paused
switch (PrinterConnectionAndCommunication.Instance.CommunicationState)
{
case PrinterConnectionAndCommunication.CommunicationStates.Printing:
case PrinterConnectionAndCommunication.CommunicationStates.Paused:
LockEditControls();
break;
}
}
}
2016-04-29 07:45:15 -07:00
ActiveTheme.ThemeChanged.RegisterEvent(ThemeChanged, ref unregisterEvents);
2015-04-08 15:20:10 -07:00
meshViewerWidget.interactionVolumes.Add(new UpArrow3D(this));
meshViewerWidget.interactionVolumes.Add(new SelectionShadow(this));
meshViewerWidget.interactionVolumes.Add(new SnappingIndicators(this));
2015-04-08 15:20:10 -07:00
PluginFinder<InteractionVolumePlugin> InteractionVolumePlugins = new PluginFinder<InteractionVolumePlugin>();
foreach (InteractionVolumePlugin plugin in InteractionVolumePlugins.Plugins)
{
meshViewerWidget.interactionVolumes.Add(plugin.CreateInteractionVolume(this));
}
2016-02-17 18:06:32 -08:00
// make sure the colors are set correct
2015-04-08 15:20:10 -07:00
ThemeChanged(this, null);
saveButtons.VisibleChanged += (sender, e) =>
{
partHasBeenEdited = true;
};
2016-02-29 14:04:52 -08:00
meshViewerWidget.ResetView();
2017-03-15 16:17:06 -07:00
if (DoBooleanTest)
{
BeforeDraw += CreateBooleanTestGeometry;
AfterDraw += RemoveBooleanTestGeometry;
}
meshViewerWidget.TrackballTumbleWidget.DrawGlContent += TrackballTumbleWidget_DrawGlContent;
}
public void SelectAll()
{
Scene.ClearSelection();
foreach(var child in Scene.Children)
{
Scene.AddToSelection(child);
}
}
private IObject3D dragDropSource;
public IObject3D DragDropSource
{
get
{
return dragDropSource;
}
set
{
if (InEditMode)
{
dragDropSource = value;
2017-03-15 16:17:06 -07:00
// Suppress ui volumes when dragDropSource is not null
meshViewerWidget.SuppressUiVolumes = (dragDropSource != null);
}
}
}
2017-03-15 16:17:06 -07:00
private void TrackballTumbleWidget_DrawGlContent(object sender, EventArgs e)
{
2017-03-15 16:17:06 -07:00
return;
if (Scene?.TraceData() != null)
{
2017-03-15 16:17:06 -07:00
Scene.TraceData().RenderBvhRecursive(Scene.Matrix, 0, 3);
}
}
public override void OnKeyDown(KeyEventArgs keyEvent)
{
if (activeButtonBeforeKeyOverride == null)
{
activeButtonBeforeKeyOverride = viewControls3D.ActiveButton;
if (keyEvent.Alt)
{
viewControls3D.ActiveButton = ViewControls3DButtons.Rotate;
}
else if (keyEvent.Shift)
{
viewControls3D.ActiveButton = ViewControls3DButtons.Translate;
}
else if (keyEvent.Control)
{
viewControls3D.ActiveButton = ViewControls3DButtons.Scale;
}
}
switch (keyEvent.KeyCode)
{
2017-03-15 16:17:06 -07:00
case Keys.A:
if (keyEvent.Control)
{
SelectAll();
keyEvent.Handled = true;
keyEvent.SuppressKeyPress = true;
}
break;
case Keys.Z:
if (keyEvent.Control)
{
UndoBuffer.Undo();
keyEvent.Handled = true;
keyEvent.SuppressKeyPress = true;
}
break;
case Keys.Y:
if (keyEvent.Control)
{
UndoBuffer.Redo();
keyEvent.Handled = true;
keyEvent.SuppressKeyPress = true;
}
break;
case Keys.Delete:
case Keys.Back:
DeleteSelectedMesh();
break;
case Keys.Escape:
if (CurrentSelectInfo.DownOnPart)
{
CurrentSelectInfo.DownOnPart = false;
2017-03-15 16:17:06 -07:00
Scene.SelectedItem.Matrix = transformOnMouseDown;
Invalidate();
}
break;
}
base.OnKeyDown(keyEvent);
}
2017-03-15 16:17:06 -07:00
public bool IsEditing { get; private set; }
2016-02-17 18:06:32 -08:00
public bool DragingPart
{
2016-02-19 08:29:49 -08:00
get { return CurrentSelectInfo.DownOnPart; }
2016-02-17 18:06:32 -08:00
}
2017-03-15 16:17:06 -07:00
public void AddUndoOperation(IUndoRedoCommand operation)
2016-02-14 17:53:44 -08:00
{
2017-03-15 16:17:06 -07:00
UndoBuffer.Add(operation);
2016-02-14 17:53:44 -08:00
}
2017-03-15 16:17:06 -07:00
#region DoBooleanTest
Object3D booleanGroup;
2016-03-12 14:16:34 -08:00
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);
2017-03-15 16:17:06 -07:00
private void CreateBooleanTestGeometry(object sender, DrawEventArgs e)
2016-03-07 14:23:22 -08:00
{
try
{
2017-03-15 16:17:06 -07:00
booleanGroup = new Object3D { ItemType = Object3DTypes.Group };
booleanGroup.Children.Add(new Object3D()
{
Mesh = ApplyBoolean(PolygonMesh.Csg.CsgOperations.Union, AxisAlignedBoundingBox.Union, new Vector3(100, 0, 20), "U")
});
2016-03-07 14:23:22 -08:00
2017-03-15 16:17:06 -07:00
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")
});
2016-03-07 14:23:22 -08:00
offset += direction;
2016-03-12 14:16:34 -08:00
rotCurrent += rotChange;
scaleCurrent += scaleChange;
2016-03-07 14:23:22 -08:00
2017-03-15 16:17:06 -07:00
Scene.ModifyChildren(children =>
{
children.Add(booleanGroup);
});
2016-03-07 14:23:22 -08:00
}
catch(Exception e2)
{
string text = e2.Message;
2017-03-15 16:17:06 -07:00
int a = 0;
2016-03-07 14:23:22 -08:00
}
}
private Mesh ApplyBoolean(Func<Mesh, Mesh, Mesh> meshOpperation, Func<AxisAlignedBoundingBox, AxisAlignedBoundingBox, AxisAlignedBoundingBox> aabbOpperation, Vector3 centering, string opp)
2016-03-07 14:23:22 -08:00
{
Mesh boxA = PlatonicSolids.CreateCube(40, 40, 40);
2017-03-15 16:17:06 -07:00
//boxA = PlatonicSolids.CreateIcosahedron(35);
2016-03-07 14:23:22 -08:00
boxA.Translate(centering);
Mesh boxB = PlatonicSolids.CreateCube(40, 40, 40);
2017-03-15 16:17:06 -07:00
//boxB = PlatonicSolids.CreateIcosahedron(35);
2016-03-07 14:23:22 -08:00
for (int i = 0; i < 3; i++)
{
if (Math.Abs(direction[i] + offset[i]) > 10)
{
2016-03-12 14:16:34 -08:00
direction[i] = direction[i] * -1.00073112;
2016-03-07 14:23:22 -08:00
}
}
2016-03-12 14:16:34 -08:00
for (int i = 0; i < 3; i++)
{
if (Math.Abs(rotChange[i] + rotCurrent[i]) > 6)
{
rotChange[i] = rotChange[i] * -1.000073112;
}
}
for (int i = 0; i < 3; i++)
{
if (scaleChange[i] + scaleCurrent[i] > 1.1 || scaleChange[i] + scaleCurrent[i] < .9)
{
scaleChange[i] = scaleChange[i] * -1.000073112;
}
}
Vector3 offsetB = offset + centering;
// switch to the failing offset
//offsetB = new Vector3(105.240172225344, 92.9716306394062, 18.4619570261172);
//rotCurrent = new Vector3(4.56890223673623, -2.67874102322035, 1.02768848238523);
//scaleCurrent = new Vector3(1.07853517569753, 0.964980885267323, 1.09290934544604);
2016-03-12 14:16:34 -08:00
Debug.WriteLine("t"+offsetB.ToString() + " r" + rotCurrent.ToString() + " s" + scaleCurrent.ToString() + " " + opp);
Matrix4X4 transformB = Matrix4X4.CreateScale(scaleCurrent) * Matrix4X4.CreateRotation(rotCurrent) * Matrix4X4.CreateTranslation(offsetB);
boxB.Transform(transformB);
Mesh meshToAdd = meshOpperation(boxA, boxB);
2016-03-07 14:23:22 -08:00
meshToAdd.CleanAndMergMesh();
if(aabbOpperation != null)
{
AxisAlignedBoundingBox boundsA = boxA.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox boundsB = boxB.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox boundsAdd = meshToAdd.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox boundsResult = aabbOpperation(boundsA, boundsB);
if(!boundsAdd.Equals(boundsResult, .0001))
{
int a = 0;
}
}
int nonManifoldEdges = meshToAdd.GetNonManifoldEdges().Count;
if (nonManifoldEdges > 0)
{
// shoud be manifold
int a = 0;
}
2016-03-07 14:23:22 -08:00
return meshToAdd;
}
2017-03-15 16:17:06 -07:00
private void RemoveBooleanTestGeometry(object sender, DrawEventArgs e)
{
2017-03-15 16:17:06 -07:00
if (meshViewerWidget.Scene.Children.Contains(booleanGroup))
2016-03-07 14:23:22 -08:00
{
2017-03-15 16:17:06 -07:00
meshViewerWidget.Scene.Children.Remove(booleanGroup);
2016-03-07 14:23:22 -08:00
UiThread.RunOnIdle(() => Invalidate(), 1.0 / 30.0);
}
}
2017-03-15 16:17:06 -07:00
#endregion DoBooleanTest
2015-04-08 15:20:10 -07:00
public enum AutoRotate { Enabled, Disabled };
2015-05-30 12:48:16 -07:00
public enum OpenMode { Viewing, Editing }
2015-05-30 12:48:16 -07:00
public enum WindowMode { Embeded, StandAlone };
2015-05-30 12:48:16 -07:00
public bool DisplayAllValueData { get; set; }
2017-03-15 16:17:06 -07:00
public WindowMode windowType { get; set; }
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
public override void OnClosed(ClosedEventArgs e)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
unregisterEvents?.Invoke(this, null);
base.OnClosed(e);
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
// TODO: Just realized we don't implement DragLeave, meaning that injected items can't be removed. Must implement
public override void OnDragDrop(FileDropEventArgs fileDropArgs)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (AllowDragDrop() && fileDropArgs.DroppedFiles.Count == 1)
{
2017-03-15 16:17:06 -07:00
// Item is already in the scene
DragDropSource = null;
}
2017-03-15 16:17:06 -07:00
else if (AllowDragDrop())
{
2017-03-15 16:17:06 -07:00
// 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)
{
2017-03-15 16:17:06 -07:00
bool enterEditModeBeforeAddingParts = enterEditButtonsContainer.Visible == true;
if (enterEditModeBeforeAddingParts)
{
2017-03-15 16:17:06 -07:00
SwitchStateToEditing();
}
2017-03-15 16:17:06 -07:00
loadAndAddPartsToPlate(partsToAdd);
}
}
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
base.OnDragDrop(fileDropArgs);
}
2017-03-15 16:17:06 -07:00
public override void OnDragEnter(FileDropEventArgs fileDropArgs)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (AllowDragDrop())
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
foreach (string file in fileDropArgs.DroppedFiles)
{
2017-03-15 16:17:06 -07:00
string extension = Path.GetExtension(file).ToLower();
2015-08-03 16:46:57 -07:00
if (extension != "" && ApplicationSettings.OpenDesignFileParams.Contains(extension))
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
fileDropArgs.AcceptDrop = true;
2015-05-30 12:48:16 -07:00
}
}
2017-03-15 16:17:06 -07:00
if(fileDropArgs.AcceptDrop)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
DragDropSource = new Object3D
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
ItemType = Object3DTypes.Model,
Mesh = PlatonicSolids.CreateCube(10, 10, 10)
};
}
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
base.OnDragEnter(fileDropArgs);
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
public override async void OnDragOver(FileDropEventArgs fileDropArgs)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (AllowDragDrop() && fileDropArgs.DroppedFiles.Count == 1)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
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))
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
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;
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
// AcceptDrop anytime a DropSource has been queued
fileDropArgs.AcceptDrop = DragDropSource != null;
base.OnDragOver(fileDropArgs);
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
private GuiWidget topMostParent;
private PlaneShape bedPlane = new PlaneShape(Vector3.UnitZ, 0, null);
/// <summary>
/// Provides a View3DWidget specific drag implementation
/// </summary>
/// <param name="screenSpaceMousePosition">The screen space mouse position.</param>
/// <returns>A value indicating in the DragDropSource was added to the scene</returns>
public bool AltDragOver(Vector2 screenSpaceMousePosition)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (this.HasBeenClosed)
{
return false;
}
bool itemAddedToScene = false;
var meshViewerPosition = this.meshViewerWidget.TransformToScreenSpace(meshViewerWidget.LocalBounds);
if (meshViewerPosition.Contains(screenSpaceMousePosition) && DragDropSource != null)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
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))
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
// 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)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
return false;
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
// 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);
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
return itemAddedToScene;
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
return false;
2015-04-08 15:20:10 -07:00
}
public override void OnLoad(EventArgs args)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
topMostParent = this.TopmostParent();
base.OnLoad(args);
}
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
/// <summary>
/// Loads the referenced DragDropSource object.
/// </summary>
/// <param name="dragSource">The drag source at the original time of invocation.</param>
/// <returns></returns>
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)
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
var selectedItem = Scene.SelectedItem;
foreach (InteractionVolume volume in meshViewerWidget.interactionVolumes)
{
2017-03-15 16:17:06 -07:00
volume.SetPosition(selectedItem);
}
2015-04-08 15:20:10 -07:00
}
2014-03-20 18:20:52 -07:00
2015-05-30 12:48:16 -07:00
hasDrawn = true;
base.OnDraw(graphics2D);
}
2015-04-08 15:20:10 -07:00
private ViewControls3DButtons? activeButtonBeforeMouseOverride = null;
private ViewControls3DButtons? activeButtonBeforeKeyOverride = null;
public override void OnKeyUp(KeyEventArgs keyEvent)
{
if (activeButtonBeforeKeyOverride != null)
{
viewControls3D.ActiveButton = (ViewControls3DButtons)activeButtonBeforeKeyOverride;
activeButtonBeforeKeyOverride = null;
}
base.OnKeyUp(keyEvent);
}
2015-05-30 12:48:16 -07:00
public override void OnMouseDown(MouseEventArgs mouseEvent)
2015-04-08 15:20:10 -07:00
{
// Show transform override
if (activeButtonBeforeMouseOverride == null && mouseEvent.Button == MouseButtons.Right)
{
activeButtonBeforeMouseOverride = viewControls3D.ActiveButton;
viewControls3D.ActiveButton = ViewControls3DButtons.Rotate;
}
else if (activeButtonBeforeMouseOverride == null && mouseEvent.Button == MouseButtons.Middle)
{
activeButtonBeforeMouseOverride = viewControls3D.ActiveButton;
viewControls3D.ActiveButton = ViewControls3DButtons.Translate;
}
2017-03-15 16:17:06 -07:00
if(mouseEvent.Button == MouseButtons.Right ||
mouseEvent.Button == MouseButtons.Middle)
{
meshViewerWidget.SuppressUiVolumes = true;
}
2015-05-30 12:48:16 -07:00
autoRotating = false;
base.OnMouseDown(mouseEvent);
2017-03-15 16:17:06 -07:00
2015-05-30 12:48:16 -07:00
if (meshViewerWidget.TrackballTumbleWidget.UnderMouseState == Agg.UI.UnderMouseState.FirstUnderMouse)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (mouseEvent.Button == MouseButtons.Left
&&
ModifierKeys == Keys.Shift ||
(
meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None
2015-05-30 12:48:16 -07:00
&& ModifierKeys != Keys.Control
2017-03-15 16:17:06 -07:00
&& ModifierKeys != Keys.Alt))
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (!meshViewerWidget.MouseDownOnInteractionVolume)
{
2017-03-15 16:17:06 -07:00
meshViewerWidget.SuppressUiVolumes = true;
2016-02-19 08:29:49 -08:00
IntersectInfo info = new IntersectInfo();
2017-03-15 16:17:06 -07:00
IObject3D hitObject = FindHitObject3D(mouseEvent.Position, ref info);
if (hitObject != null)
2015-05-30 12:48:16 -07:00
{
2016-02-19 08:29:49 -08:00
CurrentSelectInfo.HitPlane = new PlaneShape(Vector3.UnitZ, CurrentSelectInfo.PlaneDownHitPos.z, null);
2014-03-20 18:20:52 -07:00
2017-03-15 16:17:06 -07:00
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;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
Invalidate();
2016-02-19 08:29:49 -08:00
CurrentSelectInfo.DownOnPart = true;
2017-03-15 16:17:06 -07:00
AxisAlignedBoundingBox selectedBounds = meshViewerWidget.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
2016-02-19 08:29:49 -08:00
if (info.hitPosition.x < selectedBounds.Center.x)
{
if (info.hitPosition.y < selectedBounds.Center.y)
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.LB;
}
else
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.LT;
}
}
else
{
if (info.hitPosition.y < selectedBounds.Center.y)
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.RB;
}
else
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.RT;
}
}
2015-05-30 12:48:16 -07:00
}
else
{
2017-03-15 16:17:06 -07:00
if(!Scene.HasSelection)
{
return;
}
if(Scene.SelectedItem.ItemType == Object3DTypes.SelectionGroup)
{
Scene.ModifyChildren(ClearSelectionApplyChanges);
}
else
{
Scene.ClearSelection();
}
2015-05-30 12:48:16 -07:00
}
SelectedTransformChanged?.Invoke(this, null);
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
}
}
2015-02-27 11:09:37 -08:00
2017-03-15 16:17:06 -07:00
public void ClearSelectionApplyChanges(List<IObject3D> target)
{
Scene.SelectedItem.CollapseInto(target);
Scene.ClearSelection();
}
public IntersectInfo GetIntersectPosition(Vector2 screenSpacePosition)
{
//Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, new Vector2(mouseEvent.X, mouseEvent.Y));
2017-03-15 16:17:06 -07:00
// Translate to local
Vector2 localPosition = this.TransformFromScreenSpace(screenSpacePosition);
Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayForLocalBounds(localPosition);
return CurrentSelectInfo.HitPlane.GetClosestIntersection(ray);
}
public void DragSelectedObject(Vector2 localMousePostion)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, localMousePostion);
Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayForLocalBounds(meshViewerWidgetScreenPosition);
IntersectInfo info = CurrentSelectInfo.HitPlane.GetClosestIntersection(ray);
if (info != null)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
// 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)
2015-02-27 11:09:37 -08:00
{
2017-03-15 16:17:06 -07:00
// 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)
2016-02-18 09:36:01 -08:00
{
2017-03-15 16:17:06 -07:00
// switch to the other side
xSnapOffset = selectedBounds.maxXYZ.x;
2016-02-18 09:36:01 -08:00
}
2017-03-15 16:17:06 -07:00
double xToSnap = xSnapOffset + delta.x;
2016-02-18 09:36:01 -08:00
2017-03-15 16:17:06 -07:00
double snappedX = ((int)((xToSnap / snapGridDistance) + .5)) * snapGridDistance;
delta.x = snappedX - xSnapOffset;
2015-02-27 11:09:37 -08:00
2017-03-15 16:17:06 -07:00
double ySnapOffset = selectedBounds.minXYZ.y;
// snap the y position
if (CurrentSelectInfo.HitQuadrant == HitQuadrant.LT
|| CurrentSelectInfo.HitQuadrant == HitQuadrant.RT)
{
2017-03-15 16:17:06 -07:00
// switch to the other side
ySnapOffset = selectedBounds.maxXYZ.y;
}
double yToSnap = ySnapOffset + delta.y;
2017-03-15 16:17:06 -07:00
double snappedY = ((int)((yToSnap / snapGridDistance) + .5)) * snapGridDistance;
delta.y = snappedY - ySnapOffset;
}
2017-03-15 16:17:06 -07:00
// move the mesh back to the new position
{
Matrix4X4 totalTransform = Matrix4X4.CreateTranslation(new Vector3(delta));
2015-02-27 11:09:37 -08:00
2017-03-15 16:17:06 -07:00
Scene.SelectedItem.Matrix *= totalTransform;
2016-02-18 09:36:01 -08:00
2017-03-15 16:17:06 -07:00
CurrentSelectInfo.LastMoveDelta = delta;
}
2016-02-18 09:36:01 -08:00
2017-03-15 16:17:06 -07:00
Invalidate();
}
}
2015-02-27 11:09:37 -08:00
2017-03-15 16:17:06 -07:00
public override void OnMouseMove(MouseEventArgs mouseEvent)
{
if (CurrentSelectInfo.DownOnPart && meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None)
{
DragSelectedObject(new Vector2(mouseEvent.X, mouseEvent.Y));
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
base.OnMouseMove(mouseEvent);
2015-04-08 15:20:10 -07:00
}
public void AddUndoForSelectedMeshGroupTransform(Matrix4X4 undoTransform)
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection && undoTransform != Scene.SelectedItem?.Matrix)
{
2017-03-15 16:17:06 -07:00
UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix));
}
}
2015-05-30 12:48:16 -07:00
public override void OnMouseUp(MouseEventArgs mouseEvent)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None
2016-02-19 08:29:49 -08:00
&& CurrentSelectInfo.DownOnPart
&& CurrentSelectInfo.LastMoveDelta != Vector3.Zero)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.SelectedItem.Matrix != transformOnMouseDown)
{
AddUndoForSelectedMeshGroupTransform(transformOnMouseDown);
PartHasBeenChanged();
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
meshViewerWidget.SuppressUiVolumes = false;
2016-02-19 08:29:49 -08:00
CurrentSelectInfo.DownOnPart = false;
2015-04-08 15:20:10 -07:00
if (activeButtonBeforeMouseOverride != null)
{
viewControls3D.ActiveButton = (ViewControls3DButtons)activeButtonBeforeMouseOverride;
activeButtonBeforeMouseOverride = null;
}
2015-05-30 12:48:16 -07:00
base.OnMouseUp(mouseEvent);
}
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
public void PartHasBeenChanged()
{
saveButtons.Visible = true;
SelectedTransformChanged?.Invoke(this, null);
2016-02-27 15:01:28 -08:00
Invalidate();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
public void ThemeChanged(object sender, EventArgs e)
{
2015-07-14 13:38:22 -07:00
processingProgressControl.FillColor = ActiveTheme.Instance.PrimaryAccentColor;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
MeshViewerWidget.SetMaterialColor(1, ActiveTheme.Instance.PrimaryAccentColor);
}
2017-03-15 16:17:06 -07:00
internal void AddMaterialControls(FlowLayoutWidget buttonPanel)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
extruderButtons.Clear();
for (int extruderIndex = 0; extruderIndex < ActiveSliceSettings.Instance.GetValue<int>(SettingsKey.extruder_count); extruderIndex++)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
FlowLayoutWidget colorSelectionContainer = new FlowLayoutWidget(FlowDirection.LeftToRight);
colorSelectionContainer.HAnchor = HAnchor.ParentLeftRight;
colorSelectionContainer.Padding = new BorderDouble(5);
2016-04-18 11:31:31 -07:00
string colorLabelText = string.Format("{0} {1}", "Material".Localize(), extruderIndex + 1);
2015-05-30 12:48:16 -07:00
RadioButton extruderSelection = new RadioButton(colorLabelText, textColor: ActiveTheme.Instance.PrimaryTextColor);
extruderButtons.Add(extruderSelection);
extruderSelection.SiblingRadioButtonList = extruderButtons;
colorSelectionContainer.AddChild(extruderSelection);
colorSelectionContainer.AddChild(new HorizontalSpacer());
int extruderIndexLocal = extruderIndex;
extruderSelection.Click += (sender, e) =>
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
{
2017-03-15 16:17:06 -07:00
// 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)
{
2017-03-15 16:17:06 -07:00
material.MaterialIndex = extruderIndexLocal + 1;
PartHasBeenChanged();
2015-04-08 15:20:10 -07:00
}
}
2015-05-30 12:48:16 -07:00
};
2014-10-13 19:29:25 -07:00
2015-05-30 12:48:16 -07:00
buttonPanel.AddChild(colorSelectionContainer);
2015-04-08 15:20:10 -07:00
}
}
2015-05-30 12:48:16 -07:00
private void AddRotateControls(FlowLayoutWidget buttonPanel)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
List<GuiWidget> rotateControls = new List<GuiWidget>();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
textImageButtonFactory.FixedWidth = EditButtonHeight;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
FlowLayoutWidget degreesContainer = new FlowLayoutWidget(FlowDirection.LeftToRight);
degreesContainer.HAnchor = HAnchor.ParentLeftRight;
degreesContainer.Padding = new BorderDouble(5);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
string degreesLabelText = "Degrees".Localize();
string degreesLabelTextFull = "{0}:".FormatWith(degreesLabelText);
TextWidget degreesLabel = new TextWidget(degreesLabelText, textColor: ActiveTheme.Instance.PrimaryTextColor);
degreesContainer.AddChild(degreesLabel);
degreesContainer.AddChild(new HorizontalSpacer());
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
MHNumberEdit degreesControl = new MHNumberEdit(45, pixelWidth: 40, allowNegatives: true, allowDecimals: true, increment: 5, minValue: -360, maxValue: 360);
degreesControl.VAnchor = Agg.UI.VAnchor.ParentTop;
degreesContainer.AddChild(degreesControl);
rotateControls.Add(degreesControl);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
buttonPanel.AddChild(degreesContainer);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
FlowLayoutWidget rotateButtonContainer = new FlowLayoutWidget(FlowDirection.LeftToRight);
rotateButtonContainer.HAnchor = HAnchor.ParentLeftRight;
2015-04-08 15:20:10 -07:00
ImageBuffer rotateImage = StaticData.Instance.LoadIcon("icon_rotate_32x32.png", 32, 32);
Button rotateXButton = textImageButtonFactory.Generate("", rotateImage);
2015-05-30 12:48:16 -07:00
TextWidget centeredX = new TextWidget("X", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor); centeredX.Margin = new BorderDouble(3, 0, 0, 0); centeredX.AnchorCenter(); rotateXButton.AddChild(centeredX);
rotateButtonContainer.AddChild(rotateXButton);
rotateControls.Add(rotateXButton);
rotateXButton.Click += (s, e) =>
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
double radians = MathHelper.DegreesToRadians(degreesControl.ActuallNumberEdit.Value);
Matrix4X4 rotation = Matrix4X4.CreateRotationX(radians);
2017-03-15 16:17:06 -07:00
Matrix4X4 undoTransform = Scene.SelectedItem.Matrix;
Scene.SelectedItem.Matrix = PlatingHelper.ApplyAtCenter(Scene.SelectedItem, rotation);
UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix));
2015-05-30 12:48:16 -07:00
PartHasBeenChanged();
Invalidate();
}
};
2015-04-08 15:20:10 -07:00
Button rotateYButton = textImageButtonFactory.Generate("", rotateImage);
2015-05-30 12:48:16 -07:00
TextWidget centeredY = new TextWidget("Y", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor); centeredY.Margin = new BorderDouble(3, 0, 0, 0); centeredY.AnchorCenter(); rotateYButton.AddChild(centeredY);
rotateButtonContainer.AddChild(rotateYButton);
rotateControls.Add(rotateYButton);
rotateYButton.Click += (s, e) =>
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
double radians = MathHelper.DegreesToRadians(degreesControl.ActuallNumberEdit.Value);
Matrix4X4 rotation = Matrix4X4.CreateRotationY(radians);
2017-03-15 16:17:06 -07:00
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();
2015-05-30 12:48:16 -07:00
Invalidate();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
};
2015-04-08 15:20:10 -07:00
Button rotateZButton = textImageButtonFactory.Generate("", rotateImage);
2015-05-30 12:48:16 -07:00
TextWidget centeredZ = new TextWidget("Z", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor); centeredZ.Margin = new BorderDouble(3, 0, 0, 0); centeredZ.AnchorCenter(); rotateZButton.AddChild(centeredZ);
rotateButtonContainer.AddChild(rotateZButton);
rotateControls.Add(rotateZButton);
rotateZButton.Click += (s, e) =>
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
double radians = MathHelper.DegreesToRadians(degreesControl.ActuallNumberEdit.Value);
Matrix4X4 rotation = Matrix4X4.CreateRotationZ(radians);
2017-03-15 16:17:06 -07:00
Matrix4X4 undoTransform = Scene.SelectedItem.Matrix;
Scene.SelectedItem.Matrix = PlatingHelper.ApplyAtCenter(Scene.SelectedItem, rotation);
UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix));
2015-05-30 12:48:16 -07:00
PartHasBeenChanged();
Invalidate();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
};
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
buttonPanel.AddChild(rotateButtonContainer);
2015-04-08 15:20:10 -07:00
Button layFlatButton = WhiteButtonFactory.Generate("Align to Bed".Localize(), centerText: true);
2015-05-30 12:48:16 -07:00
layFlatButton.Cursor = Cursors.Hand;
buttonPanel.AddChild(layFlatButton);
2015-04-08 15:20:10 -07:00
layFlatButton.Click += (s, e) =>
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
Matrix4X4 undoTransform = Scene.SelectedItem.Matrix;
MakeLowestFaceFlat(Scene.SelectedItem);
UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix));
2015-05-30 12:48:16 -07:00
PartHasBeenChanged();
Invalidate();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
};
2015-04-08 15:20:10 -07:00
buttonPanel.AddChild(GenerateHorizontalRule());
2015-05-30 12:48:16 -07:00
textImageButtonFactory.FixedWidth = 0;
2015-04-08 15:20:10 -07:00
}
private void AddSaveAndSaveAs(FlowLayoutWidget flowToAddTo)
{
TupleList<string, Func<bool>> buttonList = new TupleList<string, Func<bool>>();
2016-01-20 10:12:01 -08:00
buttonList.Add("Save".Localize(), () =>
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if(printItemWrapper == null)
{
UiThread.RunOnIdle(OpenSaveAsWindow);
}
else
{
SaveChanges(null);
}
2015-04-08 15:20:10 -07:00
return true;
});
2016-01-20 10:12:01 -08:00
buttonList.Add("Save As".Localize(), () =>
2015-04-08 15:20:10 -07:00
{
UiThread.RunOnIdle(OpenSaveAsWindow);
2015-04-08 15:20:10 -07:00
return true;
});
2015-08-10 13:36:31 -07:00
2015-04-08 15:20:10 -07:00
SplitButtonFactory splitButtonFactory = new SplitButtonFactory();
splitButtonFactory.FixedHeight = 40 * GuiWidget.DeviceScale;
2017-03-15 16:17:06 -07:00
2015-04-08 15:20:10 -07:00
saveButtons = splitButtonFactory.Generate(buttonList, Direction.Up, imageName: "icon_save_32x32.png");
saveButtons.Visible = false;
saveButtons.Margin = new BorderDouble();
saveButtons.VAnchor |= VAnchor.ParentCenter;
2015-04-08 15:20:10 -07:00
flowToAddTo.AddChild(saveButtons);
}
2015-05-30 12:48:16 -07:00
private bool AllowDragDrop()
2017-03-15 16:17:06 -07:00
{
if ((!enterEditButtonsContainer.Visible
2015-05-30 12:48:16 -07:00
&& !doEdittingButtonsContainer.Visible)
2017-03-15 16:17:06 -07:00
|| printItemWrapper != null && printItemWrapper.PrintItem.ReadOnly)
2015-05-30 12:48:16 -07:00
{
return false;
}
return true;
}
private void AutoSpin()
2015-05-30 12:48:16 -07:00
{
if (!HasBeenClosed && autoRotating)
2015-05-30 12:48:16 -07:00
{
// add it back in to keep it running.
UiThread.RunOnIdle(AutoSpin, .04);
if ((!timeSinceLastSpin.IsRunning || timeSinceLastSpin.ElapsedMilliseconds > 50)
&& hasDrawn)
{
hasDrawn = false;
timeSinceLastSpin.Restart();
Quaternion currentRotation = meshViewerWidget.TrackballTumbleWidget.TrackBallController.CurrentRotation.GetRotation();
Quaternion invertedRotation = Quaternion.Invert(currentRotation);
Quaternion rotateAboutZ = Quaternion.FromEulerAngles(new Vector3(0, 0, .01));
rotateAboutZ = invertedRotation * rotateAboutZ * currentRotation;
meshViewerWidget.TrackballTumbleWidget.TrackBallController.Rotate(rotateAboutZ);
Invalidate();
}
}
}
private void ReportProgressChanged(double progress0To1, string processingState)
{
bool continueProcessing;
ReportProgressChanged(progress0To1, processingState, out continueProcessing);
}
private void ReportProgressChanged(double progress0To1, string processingState, out bool continueProcessing)
2015-05-30 12:48:16 -07:00
{
if (!timeSinceReported.IsRunning || timeSinceReported.ElapsedMilliseconds > 100
|| processingState != processingProgressControl.ProgressMessage)
{
UiThread.RunOnIdle(() =>
2015-05-30 12:48:16 -07:00
{
2015-07-14 13:38:22 -07:00
processingProgressControl.RatioComplete = progress0To1;
2015-05-30 12:48:16 -07:00
processingProgressControl.ProgressMessage = processingState;
});
timeSinceReported.Restart();
}
continueProcessing = true;
}
2017-03-15 16:17:06 -07:00
public async Task ClearBedAndLoadPrintItemWrapper(PrintItemWrapper newPrintItem, bool switchToEditingMode = false)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if(switchToEditingMode)
{
SwitchStateToEditing();
}
else
{
SwitchStateToNotEditing();
}
Scene.ModifyChildren(children => children.Clear());
PrintItemWrapper.FileHasChanged.UnregisterEvent(ReloadMeshIfChangeExternaly, ref unregisterEvents);
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
if (newPrintItem != null)
2015-05-30 12:48:16 -07:00
{
// remove it first to make sure we don't double add it
2015-09-23 13:33:14 -07:00
PrintItemWrapper.FileHasChanged.UnregisterEvent(ReloadMeshIfChangeExternaly, ref unregisterEvents);
2016-12-01 15:14:53 -08:00
PrintItemWrapper.FileHasChanged.RegisterEvent(ReloadMeshIfChangeExternaly, ref unregisterEvents);
2015-05-30 12:48:16 -07:00
// don't load the mesh until we get all the rest of the interface built
meshViewerWidget.LoadDone += new EventHandler(meshViewerWidget_LoadDone);
Vector2 bedCenter = new Vector2();
MeshViewerWidget.CenterPartAfterLoad doCentering = MeshViewerWidget.CenterPartAfterLoad.DONT;
if (ActiveSliceSettings.Instance?.GetValue<bool>(SettingsKey.center_part_on_bed) == true)
{
doCentering = MeshViewerWidget.CenterPartAfterLoad.DO;
bedCenter = ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.print_center);
}
2017-03-15 16:17:06 -07:00
await meshViewerWidget.LoadItemIntoScene(newPrintItem.FileLocation, doCentering, bedCenter, newPrintItem.Name);
Invalidate();
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
this.printItemWrapper = newPrintItem;
PartHasBeenChanged();
2015-05-30 12:48:16 -07:00
partHasBeenEdited = false;
}
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
private void CreateOptionsContent()
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
AddRotateControls(Sidebar.rotateOptionContainer);
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
internal void CreateRenderTypeRadioButtons(FlowLayoutWidget viewOptionContainer)
2015-05-30 12:48:16 -07:00
{
string renderTypeString = UserSettings.Instance.get(UserSettingsKey.defaultRenderSetting);
2015-05-30 12:48:16 -07:00
if (renderTypeString == null)
{
if (UserSettings.Instance.IsTouchScreen)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
renderTypeString = "Shaded";
2015-04-08 15:20:10 -07:00
}
else
{
2015-05-30 12:48:16 -07:00
renderTypeString = "Outlines";
2015-04-08 15:20:10 -07:00
}
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, renderTypeString);
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
RenderOpenGl.RenderTypes renderType;
bool canParse = Enum.TryParse<RenderOpenGl.RenderTypes>(renderTypeString, out renderType);
if (canParse)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
meshViewerWidget.RenderType = renderType;
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
RadioButton renderTypeCheckBox = new RadioButton("Shaded".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Shaded);
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (renderTypeCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Shaded;
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString());
}
2015-05-30 12:48:16 -07:00
};
2017-03-15 16:17:06 -07:00
viewOptionContainer.AddChild(renderTypeCheckBox);
2015-04-08 15:20:10 -07:00
}
{
2017-03-15 16:17:06 -07:00
RadioButton renderTypeCheckBox = new RadioButton("Outlines".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Outlines);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (renderTypeCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Outlines;
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString());
}
2015-05-30 12:48:16 -07:00
};
2017-03-15 16:17:06 -07:00
viewOptionContainer.AddChild(renderTypeCheckBox);
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
RadioButton renderTypeCheckBox = new RadioButton("Polygons".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Polygons);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (renderTypeCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Polygons;
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString());
}
2015-05-30 12:48:16 -07:00
};
2017-03-15 16:17:06 -07:00
viewOptionContainer.AddChild(renderTypeCheckBox);
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
RadioButton renderTypeCheckBox = new RadioButton("Overhang".Localize(), textColor: ActiveTheme.Instance.PrimaryTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Overhang);
2017-03-15 16:17:06 -07:00
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
{
2017-03-15 16:17:06 -07:00
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();
2017-03-15 16:17:06 -07:00
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
}
}
};
2017-03-15 16:17:06 -07:00
viewOptionContainer.AddChild(renderTypeCheckBox);
}
2017-03-15 16:17:06 -07:00
}
2017-03-15 16:17:06 -07:00
public List<IObject3DEditor> objectEditors = new List<IObject3DEditor>();
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
public Dictionary<Type, HashSet<IObject3DEditor>> objectEditorsByType = new Dictionary<Type, HashSet<IObject3DEditor>>();
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
private void Scene_SelectionChanged(object sender, EventArgs e)
{
if (!Scene.HasSelection)
{
selectedObjectPanel.RemoveAllChildren();
return;
}
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
var selectedItem = Scene.SelectedItem;
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
HashSet<IObject3DEditor> mappedEditors;
objectEditorsByType.TryGetValue(selectedItem.GetType(), out mappedEditors);
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
if(mappedEditors == null)
{
foreach(var editor in objectEditorsByType)
2016-03-04 10:11:05 -08:00
{
2017-03-15 16:17:06 -07:00
if (selectedItem.GetType().IsSubclassOf(editor.Key))
{
mappedEditors = editor.Value;
break;
}
2016-03-04 10:11:05 -08:00
}
2017-03-15 16:17:06 -07:00
}
2016-03-04 10:11:05 -08:00
2017-03-15 16:17:06 -07:00
editorPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.FitToChildren
};
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
if (mappedEditors != null)
{
var dropDownList = new DropDownList("", maxHeight: 300)
{
Margin = new BorderDouble(0, 3)
};
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
foreach (IObject3DEditor editor in mappedEditors)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
MenuItem menuItem = dropDownList.AddItem(editor.Name);
menuItem.Selected += (s, e2) =>
{
ShowObjectEditor(editor);
};
}
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
selectedObjectPanel.RemoveAllChildren();
selectedObjectPanel.AddChild(dropDownList);
selectedObjectPanel.AddChild(editorPanel);
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
// 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();
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
if(activeEditor == null)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
activeEditor = mappedEditors.First();
}
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
int selectedIndex = 0;
for(int i = 0; i < dropDownList.MenuItems.Count; i++)
{
if(dropDownList.MenuItems[i].Text == activeEditor.Name)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
selectedIndex = i;
break;
2015-05-30 12:48:16 -07:00
}
}
2017-03-15 16:17:06 -07:00
dropDownList.SelectedIndex = selectedIndex;
2016-02-14 17:53:44 -08:00
2017-03-15 16:17:06 -07:00
ShowObjectEditor(activeEditor);
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
}
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
private void ShowObjectEditor(IObject3DEditor editor)
{
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
editorPanel.CloseAllChildren();
var newEditor = editor.Create(Scene.SelectedItem, this);
editorPanel.AddChild(newEditor);
2015-05-30 12:48:16 -07:00
}
private void DeleteSelectedMesh()
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection && Scene.Children.Count > 1)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
// Create and perform the delete operation
var deleteOperation = new DeleteCommand(this, Scene.SelectedItem);
deleteOperation.Do();
2016-02-27 15:01:28 -08:00
2017-03-15 16:17:06 -07:00
// Store the operation for undo/redo
UndoBuffer.Add(deleteOperation);
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
}
2014-01-29 19:09:30 -08:00
2017-03-15 16:17:06 -07:00
private void DrawStuffForSelectedPart(Graphics2D graphics2D)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
AxisAlignedBoundingBox selectedBounds = Scene.SelectedItem.GetAxisAlignedBoundingBox(Scene.SelectedItem.Matrix);
Vector3 boundsCenter = selectedBounds.Center;
Vector3 centerTop = new Vector3(boundsCenter.x, boundsCenter.y, selectedBounds.maxXYZ.z);
2014-01-29 19:09:30 -08:00
2017-03-15 16:17:06 -07:00
Vector2 centerTopScreenPosition = meshViewerWidget.TrackballTumbleWidget.GetScreenPosition(centerTop);
centerTopScreenPosition = meshViewerWidget.TransformToParentSpace(this, centerTopScreenPosition);
//graphics2D.Circle(screenPosition.x, screenPosition.y, 5, RGBA_Bytes.Cyan);
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
PathStorage zArrow = new PathStorage();
zArrow.MoveTo(-6, -2);
zArrow.curve3(0, -4);
zArrow.LineTo(6, -2);
zArrow.LineTo(0, 12);
zArrow.LineTo(-6, -2);
2017-03-15 16:17:06 -07:00
VertexSourceApplyTransform translate = new VertexSourceApplyTransform(zArrow, Affine.NewTranslation(centerTopScreenPosition));
//graphics2D.Render(translate, RGBA_Bytes.Black);
}
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
private void ExitEditingAndSaveIfRequested(bool userResponseYesSave)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (userResponseYesSave)
{
2017-03-15 16:17:06 -07:00
SaveChanges(null, SwitchStateToNotEditing);
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
else
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
// Discard changes in scene, revert back to original state
SwitchStateToNotEditing();
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
// and reload the part
ClearBedAndLoadPrintItemWrapper(printItemWrapper);
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
private async void LoadAndAddPartsToPlate(string[] filesToLoad)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasChildren && filesToLoad != null && filesToLoad.Length > 0)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
processingProgressControl.ProcessType = "Loading Parts".Localize() + ":";
2015-05-30 12:48:16 -07:00
processingProgressControl.Visible = true;
processingProgressControl.PercentComplete = 0;
LockEditControls();
2015-04-08 15:20:10 -07:00
await Task.Run(() => loadAndAddPartsToPlate(filesToLoad));
2015-04-08 15:20:10 -07:00
if (HasBeenClosed)
{
return;
}
UnlockEditControls();
PartHasBeenChanged();
2017-03-15 16:17:06 -07:00
bool addingOnlyOneItem = Scene.Children.Count == Scene.Children.Count + 1;
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
if (Scene.HasChildren)
{
if (addingOnlyOneItem)
{
// if we are only adding one part to the plate set the selection to it
2017-03-15 16:17:06 -07:00
Scene.SelectLastChild();
}
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
}
2014-01-29 19:09:30 -08:00
private void loadAndAddPartsToPlate(string[] filesToLoadIncludingZips)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
2017-03-15 16:17:06 -07:00
if (filesToLoadIncludingZips?.Any() == true)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
List<string> filesToLoad = new List<string>();
foreach (string loadedFileName in filesToLoadIncludingZips)
2015-05-30 12:48:16 -07:00
{
string extension = Path.GetExtension(loadedFileName).ToUpper();
2015-08-03 16:46:57 -07:00
if ((extension != "" && MeshFileIo.ValidFileExtensions().Contains(extension)))
2015-05-30 12:48:16 -07:00
{
filesToLoad.Add(loadedFileName);
}
else if (extension == ".ZIP")
{
2017-03-15 16:17:06 -07:00
List<PrintItem> partFiles = ProjectFileHandler.ImportFromProjectArchive(loadedFileName);
2015-05-30 12:48:16 -07:00
if (partFiles != null)
{
foreach (PrintItem part in partFiles)
{
filesToLoad.Add(part.FileLocation);
}
}
}
}
2015-05-30 12:48:16 -07:00
string progressMessage = "Loading Parts...".Localize();
2017-03-15 16:17:06 -07:00
2015-05-30 12:48:16 -07:00
double ratioPerFile = 1.0 / filesToLoad.Count;
double currentRatioDone = 0;
2017-03-15 16:17:06 -07:00
var itemCache = new Dictionary<string, IObject3D>();
foreach (string loadedFileName in filesToLoad)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
IObject3D newItem = Object3D.Load(loadedFileName, itemCache, (double progress0To1, string processingState, out bool continueProcessing) =>
2015-05-30 12:48:16 -07:00
{
continueProcessing = !this.HasBeenClosed;
2015-05-30 12:48:16 -07:00
double ratioAvailable = (ratioPerFile * .5);
double currentRatio = currentRatioDone + progress0To1 * ratioAvailable;
ReportProgressChanged(currentRatio, progressMessage, out continueProcessing);
2015-05-30 12:48:16 -07:00
});
2014-01-29 19:09:30 -08:00
if (HasBeenClosed)
2015-05-30 12:48:16 -07:00
{
return;
}
2014-01-29 19:09:30 -08:00
2017-03-15 16:17:06 -07:00
if (newItem != null)
{
Scene.ModifyChildren(children => children.Add(newItem));
2014-01-29 19:09:30 -08:00
2017-03-15 16:17:06 -07:00
PlatingHelper.MoveToOpenPosition(newItem, this.Scene);
2014-01-29 19:09:30 -08:00
2017-03-15 16:17:06 -07:00
// TODO: There should be a batch insert so you can undo large 'add to scene' operations in one go
//this.InsertNewItem(tempScene);
2015-05-30 12:48:16 -07:00
}
2014-01-29 19:09:30 -08:00
2015-05-30 12:48:16 -07:00
currentRatioDone += ratioPerFile;
}
}
}
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
public void LockEditControls()
2015-05-30 12:48:16 -07:00
{
viewIsInEditModePreLock = doEdittingButtonsContainer.Visible;
enterEditButtonsContainer.Visible = false;
doEdittingButtonsContainer.Visible = false;
buttonRightPanelDisabledCover.Visible = true;
if (viewControls3D.PartSelectVisible == true)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
viewControls3D.PartSelectVisible = false;
if (viewControls3D.ActiveButton == ViewControls3DButtons.PartSelect)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
wasInSelectMode = true;
viewControls3D.ActiveButton = ViewControls3DButtons.Rotate;
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
}
2014-01-29 19:09:30 -08:00
2017-03-15 16:17:06 -07:00
private void MakeLowestFaceFlat(IObject3D objectToLayFlatGroup)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
Matrix4X4 objectToWold = objectToLayFlatGroup.Matrix;
IObject3D objectToLayFlat = objectToLayFlatGroup.Children[0];
Vertex lowestVertex = objectToLayFlat.Mesh.Vertices[0];
Vector3 lowestVertexPosition = Vector3.Transform(lowestVertex.Position, objectToWold);
2017-03-15 16:17:06 -07:00
IObject3D itemToLayFlat = null;
// Process each child, checking for the lowest vertex
foreach (IObject3D itemToCheck in objectToLayFlat.Children.Where(child => child.Mesh != null))
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
// find the lowest point on the model
2017-03-15 16:17:06 -07:00
for (int testIndex = 1; testIndex < itemToCheck.Mesh.Vertices.Count; testIndex++)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
Vertex vertex = itemToCheck.Mesh.Vertices[testIndex];
Vector3 vertexPosition = Vector3.Transform(vertex.Position, objectToWold);
2015-05-30 12:48:16 -07:00
if (vertexPosition.z < lowestVertexPosition.z)
{
2017-03-15 16:17:06 -07:00
lowestVertex = itemToCheck.Mesh.Vertices[testIndex];
2015-05-30 12:48:16 -07:00
lowestVertexPosition = vertexPosition;
2017-03-15 16:17:06 -07:00
itemToLayFlat = itemToCheck;
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
}
2014-01-29 19:09:30 -08:00
2015-05-30 12:48:16 -07:00
Face faceToLayFlat = null;
double lowestAngleOfAnyFace = double.MaxValue;
// Check all the faces that are connected to the lowest point to find out which one to lay flat.
foreach (Face face in lowestVertex.ConnectedFaces())
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
double biggestAngleToFaceVertex = double.MinValue;
foreach (Vertex faceVertex in face.Vertices())
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (faceVertex != lowestVertex)
{
2017-03-15 16:17:06 -07:00
Vector3 faceVertexPosition = Vector3.Transform(faceVertex.Position, objectToWold);
2015-05-30 12:48:16 -07:00
Vector3 pointRelLowest = faceVertexPosition - lowestVertexPosition;
double xLeg = new Vector2(pointRelLowest.x, pointRelLowest.y).Length;
double yLeg = pointRelLowest.z;
double angle = Math.Atan2(yLeg, xLeg);
if (angle > biggestAngleToFaceVertex)
{
biggestAngleToFaceVertex = angle;
}
}
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
if (biggestAngleToFaceVertex < lowestAngleOfAnyFace)
{
lowestAngleOfAnyFace = biggestAngleToFaceVertex;
faceToLayFlat = face;
}
}
2014-01-29 19:09:30 -08:00
2015-05-30 12:48:16 -07:00
double maxDistFromLowestZ = 0;
List<Vector3> faceVertexes = new List<Vector3>();
foreach (Vertex vertex in faceToLayFlat.Vertices())
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
Vector3 vertexPosition = Vector3.Transform(vertex.Position, objectToWold);
2015-05-30 12:48:16 -07:00
faceVertexes.Add(vertexPosition);
maxDistFromLowestZ = Math.Max(maxDistFromLowestZ, vertexPosition.z - lowestVertexPosition.z);
}
2015-05-30 12:48:16 -07:00
if (maxDistFromLowestZ > .001)
{
Vector3 xPositive = (faceVertexes[1] - faceVertexes[0]).GetNormal();
Vector3 yPositive = (faceVertexes[2] - faceVertexes[0]).GetNormal();
Vector3 planeNormal = Vector3.Cross(xPositive, yPositive).GetNormal();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
// this code takes the minimum rotation required and looks much better.
Quaternion rotation = new Quaternion(planeNormal, new Vector3(0, 0, -1));
Matrix4X4 partLevelMatrix = Matrix4X4.CreateRotation(rotation);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
// rotate it
2017-03-15 16:17:06 -07:00
objectToLayFlatGroup.Matrix = PlatingHelper.ApplyAtCenter(objectToLayFlatGroup, partLevelMatrix);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
PartHasBeenChanged();
Invalidate();
}
}
public static Regex fileNameNumberMatch = new Regex("\\(\\d+\\)", RegexOptions.Compiled);
2017-03-15 16:17:06 -07:00
private GuiWidget selectedObjectPanel;
private FlowLayoutWidget editorPanel;
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
private async void SaveChanges(SaveAsWindow.SaveAsReturnInfo returnInfo = null, Action eventToCallAfterSave = null)
{
editorThatRequestedSave = true;
afterSaveCallback = eventToCallAfterSave;
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
if (Scene.HasChildren)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
processingProgressControl.ProcessType = "Saving".Localize() + ":";
processingProgressControl.Visible = true;
processingProgressControl.PercentComplete = 0;
2017-03-15 16:17:06 -07:00
LockEditControls();
2017-03-15 16:17:06 -07:00
// Perform the actual save operation
await Task.Run(() =>
{
2017-03-15 16:17:06 -07:00
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
2017-03-15 16:17:06 -07:00
try
{
2017-03-15 16:17:06 -07:00
// If null we are replacing a file from the current print item wrapper
if (returnInfo == null)
{
2017-03-15 16:17:06 -07:00
// Only save as .mcx
if (Path.GetExtension(printItemWrapper.FileLocation) != ".mcx")
{
printItemWrapper.FileLocation = Path.ChangeExtension(printItemWrapper.FileLocation, ".mcx");
}
}
2017-03-15 16:17:06 -07:00
else // Otherwise we are saving a new file
{
2017-03-15 16:17:06 -07:00
printItemWrapper = new PrintItemWrapper(
new PrintItem()
{
Name = returnInfo.newName,
FileLocation = Path.ChangeExtension(returnInfo.fileNameAndPath, ".mcx")
},
returnInfo.destinationLibraryProvider.GetProviderLocator());
}
2017-03-15 16:17:06 -07:00
// TODO: Hook up progress reporting
Scene.Save(printItemWrapper.FileLocation, ApplicationDataStorage.Instance.ApplicationLibraryDataPath);
2017-03-15 16:17:06 -07:00
printItemWrapper.PrintItem.Commit();
2017-03-15 16:17:06 -07:00
// Wait for a second to report the file changed to give the OS a chance to finish closing it.
UiThread.RunOnIdle(printItemWrapper.ReportFileChange, 3);
2017-03-15 16:17:06 -07:00
// Save to the destination provider, otherwise it already exists and has a file monitor
if (returnInfo?.destinationLibraryProvider != null)
{
2017-03-15 16:17:06 -07:00
// save this part to correct library provider
LibraryProvider libraryToSaveTo = returnInfo.destinationLibraryProvider;
if (libraryToSaveTo != null)
{
2017-03-15 16:17:06 -07:00
libraryToSaveTo.AddItem(printItemWrapper);
libraryToSaveTo.Dispose();
}
}
2017-03-15 16:17:06 -07:00
saveSucceded = true;
}
2017-03-15 16:17:06 -07:00
catch (Exception ex)
{
Trace.WriteLine("Error saving file: ", ex.Message);
}
2017-03-15 16:17:06 -07:00
});
2015-09-23 13:33:14 -07:00
2017-03-15 16:17:06 -07:00
// Post Save cleanup
if (this.HasBeenClosed)
{
2017-03-15 16:17:06 -07:00
return;
}
2015-11-04 17:42:07 -08:00
2017-03-15 16:17:06 -07:00
UnlockEditControls();
saveButtons.Visible = !saveSucceded;
afterSaveCallback?.Invoke();
2015-04-08 15:20:10 -07:00
}
}
2015-05-30 12:48:16 -07:00
private void meshViewerWidget_LoadDone(object sender, EventArgs e)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (windowType == WindowMode.Embeded)
{
switch (PrinterConnectionAndCommunication.Instance.CommunicationState)
{
case PrinterConnectionAndCommunication.CommunicationStates.Printing:
case PrinterConnectionAndCommunication.CommunicationStates.Paused:
break;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
default:
UnlockEditControls();
break;
}
}
else
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
UnlockEditControls();
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
// 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;
}
}
}
2015-04-08 15:20:10 -07:00
if (openMode == OpenMode.Editing)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
UiThread.RunOnIdle(SwitchStateToEditing);
2015-05-30 12:48:16 -07:00
}
}
2015-04-08 15:20:10 -07:00
private bool PartsAreInPrintVolume()
{
if (ActiveSliceSettings.Instance?.GetValue<bool>(SettingsKey.center_part_on_bed) == false)
{
2017-03-15 16:17:06 -07:00
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<Vector2>(SettingsKey.bed_size).x, ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.bed_size).y);
bedRect.Offset(ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.print_center) - ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.bed_size) / 2);
bool inBounds = bedRect.Contains(new Vector2(allBounds.minXYZ)) && bedRect.Contains(new Vector2(allBounds.maxXYZ));
return onBed && inBounds;
}
return true;
}
2015-05-30 12:48:16 -07:00
private void OpenExportWindow()
{
if (exportingWindow == null)
{
exportingWindow = new ExportPrintItemWindow(this.printItemWrapper);
exportingWindow.Closed += (sender, e) =>
{
exportingWindow = null;
};
exportingWindow.ShowAsSystemWindow();
}
else
{
exportingWindow.BringToFront();
}
}
2014-01-29 19:09:30 -08:00
private void OpenSaveAsWindow()
2015-05-30 12:48:16 -07:00
{
if (saveAsWindow == null)
{
2017-03-15 16:17:06 -07:00
saveAsWindow = new SaveAsWindow(SaveChanges, printItemWrapper?.SourceLibraryProviderLocator, true, true);
saveAsWindow.Closed += SaveAsWindow_Closed;
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
else
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
saveAsWindow.BringToFront();
}
}
private void ReloadMeshIfChangeExternaly(Object sender, EventArgs e)
{
2015-09-23 13:33:14 -07:00
PrintItemWrapper senderItem = sender as PrintItemWrapper;
if (senderItem != null
&& senderItem.FileLocation == printItemWrapper.FileLocation)
2015-05-30 12:48:16 -07:00
{
2015-09-23 13:33:14 -07:00
if (!editorThatRequestedSave)
{
ClearBedAndLoadPrintItemWrapper(printItemWrapper);
}
2015-09-23 13:33:14 -07:00
editorThatRequestedSave = false;
}
2015-05-30 12:48:16 -07:00
}
private bool rotateQueueMenu_Click()
{
return true;
}
private void SaveAsWindow_Closed(object sender, ClosedEventArgs e)
2015-05-30 12:48:16 -07:00
{
this.saveAsWindow = null;
}
private bool scaleQueueMenu_Click()
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
return true;
}
2015-05-30 12:48:16 -07:00
private void SetEditControlsBasedOnPrinterState(object sender, EventArgs e)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (windowType == WindowMode.Embeded)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
switch (PrinterConnectionAndCommunication.Instance.CommunicationState)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
case PrinterConnectionAndCommunication.CommunicationStates.Printing:
case PrinterConnectionAndCommunication.CommunicationStates.Paused:
LockEditControls();
break;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
default:
UnlockEditControls();
break;
2015-04-08 15:20:10 -07:00
}
}
}
2016-12-06 16:22:28 -08:00
public override bool InEditMode
{
2017-03-15 16:17:06 -07:00
get { return Sidebar != null && Sidebar.Visible; }
2016-12-06 16:22:28 -08:00
}
2015-05-30 12:48:16 -07:00
private void SwitchStateToNotEditing()
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
IsEditing = false;
2015-05-30 12:48:16 -07:00
if (!enterEditButtonsContainer.Visible)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
enterEditButtonsContainer.Visible = true;
processingProgressControl.Visible = false;
2017-03-15 16:17:06 -07:00
Sidebar.Visible = false;
2015-05-30 12:48:16 -07:00
doEdittingButtonsContainer.Visible = false;
viewControls3D.PartSelectVisible = false;
if (viewControls3D.ActiveButton == ViewControls3DButtons.PartSelect)
2015-04-08 15:20:10 -07:00
{
viewControls3D.ActiveButton = ViewControls3DButtons.Rotate;
}
2017-03-15 16:17:06 -07:00
Scene.ModifyChildren(ClearSelectionApplyChanges);
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
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()
2015-05-30 12:48:16 -07:00
{
buttonRightPanelDisabledCover.Visible = false;
processingProgressControl.Visible = false;
if (viewIsInEditModePreLock)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (!enterEditButtonsContainer.Visible)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
viewControls3D.PartSelectVisible = true;
doEdittingButtonsContainer.Visible = true;
2015-04-08 15:20:10 -07:00
}
}
2015-05-30 12:48:16 -07:00
else
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
enterEditButtonsContainer.Visible = true;
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
if (wasInSelectMode)
2015-04-08 15:20:10 -07:00
{
viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect;
2015-05-30 12:48:16 -07:00
wasInSelectMode = false;
}
2015-04-08 15:20:10 -07:00
SelectedTransformChanged?.Invoke(this, null);
2015-04-08 15:20:10 -07:00
}
2016-02-19 08:29:49 -08:00
}
2015-05-30 12:48:16 -07:00
2016-02-19 08:29:49 -08:00
public enum HitQuadrant { LB, LT, RB, RT }
public class MeshSelectInfo
{
public HitQuadrant HitQuadrant;
public bool DownOnPart;
public PlaneShape HitPlane;
public Vector3 LastMoveDelta;
public Vector3 PlaneDownHitPos;
2015-04-08 15:20:10 -07:00
}
}