mattercontrol/PartPreviewWindow/View3D/View3DWidget.cs

2684 lines
78 KiB
C#
Raw Normal View History

2014-01-29 19:09:30 -08:00
/*
Copyright (c) 2017, Lars Brubaker, John Lewin
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 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;
using System.Threading;
using System.Threading.Tasks;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.ImageProcessing;
2017-07-10 14:00:27 -07:00
using MatterHackers.Agg.OpenGlGui;
using MatterHackers.Agg.Platform;
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.Library;
using MatterHackers.MatterControl.PrinterCommunication;
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.RayTracer;
using MatterHackers.RenderOpenGl;
using MatterHackers.VectorMath;
2014-01-29 19:09:30 -08:00
namespace MatterHackers.MatterControl.PartPreviewWindow
{
public class View3DWidget : GuiWidget
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
private bool DoBooleanTest = false;
2017-04-05 19:03:04 -07:00
private bool deferEditorTillMouseUp = false;
2017-08-07 07:37:47 -07:00
public FlowLayoutWidget selectionActionBar;
public readonly int EditButtonHeight = 44;
2017-03-15 16:17:06 -07:00
2015-05-30 12:48:16 -07:00
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;
internal bool partHasBeenEdited = false;
2017-03-15 16:17:06 -07:00
private PrintItemWrapper printItemWrapper { get; set; }
internal ProgressControl processingProgressControl;
2015-05-30 12:48:16 -07:00
private SaveAsWindow saveAsWindow = null;
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
internal 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;
public static ImageBuffer ArrowRight
{
get
{
2016-10-10 15:16:26 -07:00
if (ActiveTheme.Instance.IsDarkTheme)
{
return AggContext.StaticData.LoadIcon("icon_arrow_right_no_border_32x32.png", 32, 32).InvertLightness();
2016-10-10 15:16:26 -07:00
}
else
{
return AggContext.StaticData.LoadIcon("icon_arrow_right_no_border_32x32.png", 32, 32);
2016-10-10 15:16:26 -07:00
}
}
}
public static ImageBuffer ArrowDown
{
get
{
2016-10-10 15:16:26 -07:00
if (ActiveTheme.Instance.IsDarkTheme)
{
return AggContext.StaticData.LoadIcon("icon_arrow_down_no_border_32x32.png", 32, 32).InvertLightness();
2016-10-10 15:16:26 -07:00
}
else
{
return AggContext.StaticData.LoadIcon("icon_arrow_down_no_border_32x32.png", 32, 32);
2016-10-10 15:16:26 -07:00
}
}
}
private ThemeConfig theme;
2017-07-10 14:00:27 -07:00
private PrinterConfig printer;
2017-09-05 18:02:19 -07:00
public Vector3 BedCenter
{
get
{
return new Vector3(printer.Bed.BedCenter);
}
}
2017-07-10 14:00:27 -07:00
// TODO: Make dynamic
2017-08-16 05:55:23 -07:00
public WorldView World { get; } = ApplicationController.Instance.Printer.Bed.World;
2017-07-10 14:00:27 -07:00
public TrackballTumbleWidget TrackballTumbleWidget { get; }
internal ViewGcodeBasic gcodeViewer;
public InteractionLayer InteractionLayer { get; }
PrinterConnection printerConnection;
public View3DWidget(PrinterConnection printerConnection, PrintItemWrapper printItemWrapper, PrinterConfig printer, AutoRotate autoRotate, ViewControls3D viewControls3D, ThemeConfig theme, OpenMode openMode = OpenMode.Viewing, MeshViewerWidget.EditorType editorType = MeshViewerWidget.EditorType.Part)
2015-05-30 12:48:16 -07:00
{
this.printerConnection = printerConnection;
2017-08-18 08:34:05 -07:00
var smallMarginButtonFactory = theme.SmallMarginButtonFactory;
this.printer = printer;
2017-08-16 05:55:23 -07:00
this.Scene = this.printer.Bed.Scene;
2017-07-10 14:00:27 -07:00
2017-08-16 05:55:23 -07:00
this.TrackballTumbleWidget = new TrackballTumbleWidget(ApplicationController.Instance.Printer.Bed.World)
2017-07-10 14:00:27 -07:00
{
TransformState = TrackBallController.MouseDownType.Rotation
};
this.TrackballTumbleWidget.AnchorAll();
this.InteractionLayer = new InteractionLayer(this.World, this.Scene.UndoBuffer, this.PartHasBeenChanged, this.Scene)
{
Name = "InteractionLayer",
};
this.InteractionLayer.AnchorAll();
this.viewControls3D = viewControls3D;
this.theme = theme;
2015-05-30 12:48:16 -07:00
this.openMode = openMode;
2017-06-13 12:31:50 -07:00
this.printItemWrapper = printItemWrapper;
this.Name = "View3DWidget";
this.BackgroundColor = ApplicationController.Instance.Theme.TabBodyBackground;
2017-08-18 08:34:05 -07:00
autoRotating = allowAutoRotate;
allowAutoRotate = (autoRotate == AutoRotate.Enabled);
viewControls3D.TransformStateChanged += ViewControls3D_TransformStateChanged;
var mainContainerTopToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
HAnchor = HAnchor.MaxFitOrStretch,
VAnchor = VAnchor.MaxFitOrStretch
};
2015-04-08 15:20:10 -07:00
2017-08-18 08:34:05 -07:00
// MeshViewer
meshViewerWidget = new MeshViewerWidget(printer, this.InteractionLayer, editorType: editorType);
2017-07-05 15:37:32 -07:00
meshViewerWidget.AnchorAll();
this.InteractionLayer.AddChild(meshViewerWidget);
2015-04-08 15:20:10 -07:00
2017-07-10 14:00:27 -07:00
// The slice layers view
gcodeViewer = new ViewGcodeBasic(printer, viewControls3D);
2017-07-10 14:00:27 -07:00
gcodeViewer.AnchorAll();
gcodeViewer.Visible = false;
this.InteractionLayer.AddChild(gcodeViewer);
2017-08-18 08:34:05 -07:00
// TumbleWidget
this.InteractionLayer.AddChild(this.TrackballTumbleWidget);
2017-08-18 12:40:49 -07:00
this.InteractionLayer.SetRenderTarget(this.meshViewerWidget);
2017-07-10 14:00:27 -07:00
mainContainerTopToBottom.AddChild(this.InteractionLayer);
2015-04-08 15:20:10 -07:00
var buttonBottomPanel = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Stretch,
Padding = ApplicationController.Instance.Theme.ToolbarPadding,
2017-08-04 15:42:23 -07:00
BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor,
};
2015-04-08 15:20:10 -07:00
HashSet<IObject3DEditor> mappedEditors;
objectEditorsByType = new Dictionary<Type, HashSet<IObject3DEditor>>();
// TODO: Consider only loading once into a static
var objectEditors = PluginFinder.CreateInstancesOf<IObject3DEditor>();
foreach (IObject3DEditor editor in objectEditors)
{
foreach (Type type in editor.SupportedTypes())
{
if (!objectEditorsByType.TryGetValue(type, out mappedEditors))
{
mappedEditors = new HashSet<IObject3DEditor>();
objectEditorsByType.Add(type, mappedEditors);
}
mappedEditors.Add(editor);
}
}
2017-03-15 16:17:06 -07:00
Scene.SelectionChanged += Scene_SelectionChanged;
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
{
2017-08-12 00:40:03 -07:00
selectionActionBar = new FlowLayoutWidget()
{
VAnchor = VAnchor.Center | VAnchor.Fit,
HAnchor = HAnchor.Stretch
};
2017-08-07 07:41:30 -07:00
processingProgressControl = new ProgressControl("", ActiveTheme.Instance.PrimaryTextColor, ActiveTheme.Instance.PrimaryAccentColor)
{
VAnchor = VAnchor.Center,
Visible = false
};
var buttonSpacing = ApplicationController.Instance.Theme.ButtonSpacing;
2014-01-29 19:09:30 -08:00
Button addButton = smallMarginButtonFactory.Generate("Insert".Localize(), AggContext.StaticData.LoadIcon("cube.png", 14, 14));
addButton.Margin = 0;
2017-08-07 07:41:30 -07:00
addButton.Click += (sender, e) =>
{
UiThread.RunOnIdle(() =>
2017-07-01 08:21:29 -07:00
{
AggContext.FileDialogs.OpenFileDialog(
2017-08-07 07:41:30 -07:00
new OpenFileDialogParams(ApplicationSettings.OpenDesignFileParams, multiSelect: true),
(openParams) =>
{
LoadAndAddPartsToPlate(openParams.FileNames);
});
2017-07-01 08:21:29 -07:00
});
2017-08-07 07:41:30 -07:00
};
selectionActionBar.AddChild(addButton);
CreateActionSeparator(selectionActionBar);
2017-08-07 07:41:30 -07:00
Button ungroupButton = smallMarginButtonFactory.Generate("Ungroup".Localize());
ungroupButton.Name = "3D View Ungroup";
ungroupButton.Margin = buttonSpacing;
2017-08-07 07:41:30 -07:00
ungroupButton.Click += (sender, e) =>
{
this.Scene.UngroupSelection(this);
};
this.Scene.SelectionChanged += (s, e) =>
{
ungroupButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(ungroupButton);
2017-08-07 07:41:30 -07:00
Button groupButton = smallMarginButtonFactory.Generate("Group".Localize());
groupButton.Name = "3D View Group";
groupButton.Margin = buttonSpacing;
2017-08-07 07:41:30 -07:00
groupButton.Click += (sender, e) =>
{
this.Scene.GroupSelection(this);
};
this.Scene.SelectionChanged += (s, e) =>
{
groupButton.Enabled = this.Scene.HasSelection
&& this.Scene.SelectedItem.ItemType != Object3DTypes.Group
&& this.Scene.SelectedItem.Children.Count > 1;
};
selectionActionBar.AddChild(groupButton);
// this is closer to the old align button
if (false)
{
2017-08-17 15:21:29 -07:00
var absoluteButton = smallMarginButtonFactory.Generate("Absolute".Localize());
absoluteButton.Margin = buttonSpacing;
absoluteButton.Click += (sender, e) =>
{
if (this.Scene.HasSelection)
{
this.Scene.SelectedItem.Matrix = Matrix4X4.Identity;
}
};
selectionActionBar.AddChild(absoluteButton);
}
// put in the material options
var alignButton = new PopupButton(smallMarginButtonFactory.Generate("Align".Localize()))
2017-08-07 07:41:30 -07:00
{
PopDirection = Direction.Up,
PopupContent = this.AddAlignControls(),
AlignToRightEdge = true,
Margin = buttonSpacing
};
this.Scene.SelectionChanged += (s, e) =>
{
alignButton.Enabled = this.Scene.HasSelection
&& this.Scene.SelectedItem.ItemType != Object3DTypes.Group
&& this.Scene.SelectedItem.Children.Count > 1;
2017-08-07 07:41:30 -07:00
};
selectionActionBar.AddChild(alignButton);
2017-08-17 15:21:29 -07:00
var layFlatButton = smallMarginButtonFactory.Generate("Lay Flat".Localize());
layFlatButton.Margin = buttonSpacing;
layFlatButton.Click += (sender, e) =>
{
if (this.Scene.HasSelection)
{
MakeLowestFaceFlat(this.Scene.SelectedItem);
}
};
this.Scene.SelectionChanged += (s, e) =>
{
layFlatButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(layFlatButton);
CreateActionSeparator(selectionActionBar);
2014-01-29 19:09:30 -08:00
2017-08-17 15:21:29 -07:00
var copyButton = smallMarginButtonFactory.Generate("Copy".Localize());
2017-08-07 07:41:30 -07:00
copyButton.Name = "3D View Copy";
copyButton.Margin = buttonSpacing;
2017-08-07 07:41:30 -07:00
copyButton.Click += (sender, e) =>
{
this.Scene.DuplicateSelection(this);
};
this.Scene.SelectionChanged += (s, e) =>
{
copyButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(copyButton);
2017-08-17 15:21:29 -07:00
var deleteButton = smallMarginButtonFactory.Generate("Remove".Localize());
2017-08-07 07:41:30 -07:00
deleteButton.Name = "3D View Remove";
deleteButton.Margin = buttonSpacing;
2017-08-07 07:41:30 -07:00
deleteButton.Click += (sender, e) =>
{
this.Scene.DeleteSelection(this);
};
this.Scene.SelectionChanged += (s, e) =>
{
deleteButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(deleteButton);
2014-12-20 09:07:13 -08:00
var mirrorView = smallMarginButtonFactory.Generate("Mirror".Localize());
var mirrorButton = new PopupButton(mirrorView)
{
PopDirection = Direction.Up,
2017-08-13 16:30:57 -07:00
PopupContent = new MirrorControls(this),
Margin = buttonSpacing,
};
this.Scene.SelectionChanged += (s, e) =>
{
mirrorButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(mirrorButton);
// put in the material options
var materialsButton = new PopupButton(smallMarginButtonFactory.Generate("Materials".Localize()))
{
PopDirection = Direction.Up,
PopupContent = this.AddMaterialControls(),
AlignToRightEdge = true,
Margin = buttonSpacing
};
this.Scene.SelectionChanged += (s, e) =>
{
materialsButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(materialsButton);
selectionActionBar.AddChild(new HorizontalSpacer());
// Bed menu
var bedMenuActions = new[]
{
new NamedAction()
{
Title = "Save".Localize(),
Action = async () =>
{
if (printItemWrapper == null)
{
UiThread.RunOnIdle(OpenSaveAsWindow);
}
else
{
await this.SaveChanges();
}
}
},
new NamedAction()
{
Title = "Save As".Localize(),
Action = () => UiThread.RunOnIdle(OpenSaveAsWindow)
},
2017-08-12 00:23:41 -07:00
new NamedAction()
2017-07-28 17:35:04 -07:00
{
2017-08-12 00:23:41 -07:00
Title = "Export".Localize() + "...",
Action = () =>
{
UiThread.RunOnIdle(OpenExportWindow);
}
},
new NamedAction()
{
Title = "Publish".Localize() + "...",
Action = () =>
{
UiThread.RunOnIdle(() => WizardWindow.Show<PublishPartToMatterHackers>());
}
},
new NamedAction()
2017-08-12 00:23:41 -07:00
{
Title = "Arrange All Parts".Localize(),
Action = () =>
{
this.Scene.AutoArrangeChildren(this);
}
},
new NamedAction() { Title = "----" },
new NamedAction()
{
Title = "Clear Bed".Localize(),
Action = () =>
{
UiThread.RunOnIdle(ApplicationController.Instance.ClearPlate);
}
}
2017-08-07 07:41:30 -07:00
};
2017-08-17 11:18:11 -07:00
bool isPrinterMode = meshViewerWidget.EditorMode == MeshViewerWidget.EditorType.Printer;
string title = isPrinterMode ? "Bed".Localize() : "Part".Localize();
var icon = isPrinterMode ? AggContext.StaticData.LoadIcon("bed.png") : AggContext.StaticData.LoadIcon("cube.png");
2017-08-17 11:18:11 -07:00
selectionActionBar.AddChild(new PopupButton(smallMarginButtonFactory.Generate(title, normalImage: icon))
2017-08-12 00:40:03 -07:00
{
PopDirection = Direction.Up,
PopupContent = ApplicationController.Instance.Theme.CreatePopupMenu(bedMenuActions),
2017-08-12 00:40:03 -07:00
AlignToRightEdge = true,
2017-08-30 16:43:58 -07:00
Margin = buttonSpacing,
Name = "Bed Options Menu",
2017-08-12 00:40:03 -07:00
});
2017-06-27 18:41:34 -07:00
}
2017-06-26 17:19:27 -07:00
2017-08-07 07:41:30 -07:00
selectionActionBar.AddChild(processingProgressControl);
buttonBottomPanel.AddChild(selectionActionBar);
2017-06-27 18:41:34 -07:00
LockEditControls();
2017-06-26 17:19:27 -07:00
2017-06-27 18:41:34 -07:00
mainContainerTopToBottom.AddChild(buttonBottomPanel);
2014-01-29 19:09:30 -08:00
2017-06-27 18:41:34 -07:00
this.AddChild(mainContainerTopToBottom);
2015-04-08 15:20:10 -07:00
this.AnchorAll();
2014-01-29 19:09:30 -08:00
2017-07-10 14:00:27 -07:00
this.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation;
2017-03-15 16:17:06 -07:00
selectedObjectPanel = new SelectedObjectPanel()
{
Margin = 5,
BackgroundColor = new RGBA_Bytes(0, 0, 0, ViewControlsBase.overlayAlpha)
2017-03-15 16:17:06 -07:00
};
AddChild(selectedObjectPanel);
2015-04-08 15:20:10 -07:00
UiThread.RunOnIdle(AutoSpin);
2014-05-27 09:16:35 -07:00
if (printer.Bed.RendererOptions.SyncToPrint)
2015-04-08 15:20:10 -07:00
{
printerConnection.CommunicationStateChanged.RegisterEvent(SetEditControlsBasedOnPrinterState, ref unregisterEvents);
// make sure we lock the controls if we are printing or paused
switch (printerConnection.CommunicationState)
2015-04-08 15:20:10 -07:00
{
case CommunicationStates.Printing:
case CommunicationStates.Paused:
LockEditControls();
break;
2015-04-08 15:20:10 -07:00
}
}
ActiveTheme.ThemeChanged.RegisterEvent((s, e) =>
{
processingProgressControl.FillColor = ActiveTheme.Instance.PrimaryAccentColor;
}, ref unregisterEvents);
2015-04-08 15:20:10 -07:00
var interactionVolumes = this.InteractionLayer.InteractionVolumes;
interactionVolumes.Add(new MoveInZControl(this.InteractionLayer));
interactionVolumes.Add(new SelectionShadow(this.InteractionLayer));
interactionVolumes.Add(new SnappingIndicators(this.InteractionLayer, this.CurrentSelectInfo));
2015-04-08 15:20:10 -07:00
var interactionVolumePlugins = PluginFinder.CreateInstancesOf<InteractionVolumePlugin>();
foreach (InteractionVolumePlugin plugin in interactionVolumePlugins)
{
interactionVolumes.Add(plugin.CreateInteractionVolume(this.InteractionLayer));
}
2017-03-15 16:17:06 -07:00
if (DoBooleanTest)
{
BeforeDraw += CreateBooleanTestGeometry;
AfterDraw += RemoveBooleanTestGeometry;
}
meshViewerWidget.AfterDraw += AfterDraw3DContent;
2017-08-18 08:34:05 -07:00
this.InteractionLayer.DrawGlContent += TrackballTumbleWidget_DrawGlContent;
2017-03-15 16:17:06 -07:00
}
private void CreateActionSeparator(GuiWidget container)
{
container.AddChild(new VerticalLine(60)
{
Margin = new BorderDouble(3, 2, 0, 2),
});
}
private void ViewControls3D_TransformStateChanged(object sender, TransformStateChangedEventArgs e)
{
switch (e.TransformMode)
{
case ViewControls3DButtons.Rotate:
2017-07-10 14:00:27 -07:00
this.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation;
break;
case ViewControls3DButtons.Translate:
2017-07-10 14:00:27 -07:00
this.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Translation;
break;
case ViewControls3DButtons.Scale:
2017-07-10 14:00:27 -07:00
this.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Scale;
break;
case ViewControls3DButtons.PartSelect:
2017-07-10 14:00:27 -07:00
this.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.None;
break;
}
}
2017-03-15 16:17:06 -07:00
public void SelectAll()
{
Scene.ClearSelection();
2017-08-28 09:14:55 -07:00
foreach (var child in Scene.Children.ToList())
2017-03-15 16:17:06 -07:00
{
Scene.AddToSelection(child);
}
}
2017-07-01 08:21:29 -07:00
public ILibraryContentStream DragSourceModel { get; set; }
// TODO: Rename to DragDropItem
2017-03-15 16:17:06 -07:00
private IObject3D dragDropSource;
2017-03-15 16:17:06 -07:00
public IObject3D DragDropSource
{
get
{
return dragDropSource;
}
set
{
2017-07-05 13:56:26 -07:00
// <IObject3D>
dragDropSource = value;
2017-07-05 13:56:26 -07:00
// Clear the DragSourceModel - <ILibraryItem>
DragSourceModel = null;
2017-07-05 13:56:26 -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, DrawEventArgs e)
{
if (CurrentSelectInfo.DownOnPart
&& TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None
&& Keyboard.IsKeyDown(Keys.ShiftKey))
{
// draw marks on the bed to show that the part is constrained to x and y
AxisAlignedBoundingBox selectedBounds = this.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
var drawCenter = CurrentSelectInfo.PlaneDownHitPos;
var drawColor = new RGBA_Bytes(RGBA_Bytes.Red, 20);
bool zBuffer = false;
for (int i = 0; i < 2; i++)
{
GLHelper.Render3DLine(World,
drawCenter - new Vector3(-50, 0, 0),
drawCenter - new Vector3(50, 0, 0), drawColor, zBuffer, 2);
GLHelper.Render3DLine(World,
drawCenter - new Vector3(0, -50, 0),
drawCenter - new Vector3(0, 50, 0), drawColor, zBuffer, 2);
drawColor = RGBA_Bytes.Black;
drawCenter.z = 0;
zBuffer = true;
}
}
// This shows the BVH as rects around the scene items
//Scene?.TraceData().RenderBvhRecursive(0, 3);
2017-07-10 14:00:27 -07:00
2017-08-16 05:55:23 -07:00
if (gcodeViewer?.loadedGCode == null || printer.Bed.GCodeRenderer == null || !gcodeViewer.Visible)
2017-07-10 14:00:27 -07:00
{
return;
}
printer.Bed.Render3DLayerFeatures(e);
}
public override void OnKeyDown(KeyEventArgs keyEvent)
{
// this must be called first to ensure we get the correct Handled state
base.OnKeyDown(keyEvent);
if (!keyEvent.Handled)
2017-06-07 15:56:02 -07:00
{
switch (keyEvent.KeyCode)
{
case Keys.A:
if (keyEvent.Control)
{
SelectAll();
keyEvent.Handled = true;
keyEvent.SuppressKeyPress = true;
}
break;
case Keys.Z:
if (keyEvent.Control)
{
this.Scene.UndoBuffer.Undo();
2017-06-07 15:56:02 -07:00
keyEvent.Handled = true;
keyEvent.SuppressKeyPress = true;
}
break;
case Keys.Y:
if (keyEvent.Control)
{
this.Scene.UndoBuffer.Redo();
2017-06-07 15:56:02 -07:00
keyEvent.Handled = true;
keyEvent.SuppressKeyPress = true;
}
break;
case Keys.Delete:
case Keys.Back:
this.Scene.DeleteSelection(this);
2017-06-07 15:56:02 -07:00
break;
2017-06-07 15:56:02 -07:00
case Keys.Escape:
if (CurrentSelectInfo.DownOnPart)
{
CurrentSelectInfo.DownOnPart = false;
2017-06-07 15:56:02 -07:00
Scene.SelectedItem.Matrix = transformOnMouseDown;
2017-06-07 15:56:02 -07:00
Invalidate();
}
break;
case Keys.Space:
this.Scene.ClearSelection();
break;
2017-06-07 15:56:02 -07:00
}
}
}
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
{
this.Scene.UndoBuffer.Add(operation);
2016-02-14 17:53:44 -08: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)
2016-03-07 14:23:22 -08:00
{
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);
Debug.WriteLine("t" + offsetB.ToString() + " r" + rotCurrent.ToString() + " s" + scaleCurrent.ToString() + " " + opp);
2016-03-12 14:16:34 -08:00
Matrix4X4 transformB = Matrix4X4.CreateScale(scaleCurrent) * Matrix4X4.CreateRotation(rotCurrent) * Matrix4X4.CreateTranslation(offsetB);
boxB.Transform(transformB);
Mesh meshToAdd = meshOpperation(boxA, boxB);
meshToAdd.CleanAndMergMesh(CancellationToken.None);
if (aabbOpperation != null)
{
AxisAlignedBoundingBox boundsA = boxA.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox boundsB = boxB.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox boundsAdd = meshToAdd.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox boundsResult = aabbOpperation(boundsA, boundsB);
}
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)
{
if (this.Scene.Children.Contains(booleanGroup))
2016-03-07 14:23:22 -08:00
{
this.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 bool DisplayAllValueData { get; set; }
2017-03-15 16:17:06 -07:00
public override void OnClosed(ClosedEventArgs e)
2015-05-30 12:48:16 -07:00
{
// Not needed but safer than without
viewControls3D.TransformStateChanged -= ViewControls3D_TransformStateChanged;
if (meshViewerWidget != null)
{
meshViewerWidget.AfterDraw -= AfterDraw3DContent;
}
2017-08-18 08:34:05 -07:00
this.InteractionLayer.DrawGlContent -= TrackballTumbleWidget_DrawGlContent;
2017-07-10 14:00:27 -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
}
public override void OnMouseEnterBounds(MouseEventArgs mouseEvent)
2015-05-30 12:48:16 -07:00
{
if (mouseEvent.DragFiles?.Count > 0)
{
if (AllowDragDrop())
{
mouseEvent.AcceptDrop = mouseEvent.DragFiles.TrueForAll(filePath => ApplicationController.Instance.IsLoadableFile(filePath));
if (mouseEvent.AcceptDrop)
2015-05-30 12:48:16 -07:00
{
2017-04-05 19:03:04 -07:00
string filePath = mouseEvent.DragFiles.FirstOrDefault();
string extensionWithoutPeriod = Path.GetExtension(filePath).Trim('.');
IContentProvider contentProvider;
if (!string.IsNullOrEmpty(filePath)
&& ApplicationController.Instance.Library.ContentProviders.TryGetValue(extensionWithoutPeriod, out contentProvider)
&& contentProvider is ISceneContentProvider)
2017-04-05 19:03:04 -07:00
{
var sceneProvider = contentProvider as ISceneContentProvider;
this.DragDropSource = sceneProvider.CreateItem(new FileSystemFileItem(filePath), null).Object3D;
2017-04-05 19:03:04 -07:00
}
else
{
this.DragDropSource = new Object3D
2017-04-05 19:03:04 -07:00
{
ItemType = Object3DTypes.Model,
Mesh = PlatonicSolids.CreateCube(10, 10, 10)
};
}
2015-05-30 12:48:16 -07:00
}
}
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
base.OnMouseEnterBounds(mouseEvent);
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>
2017-04-05 19:03:04 -07:00
/// <returns>A value indicating if a new item was generated for the DragDropSource and added to the scene</returns>
2017-03-15 16:17:06 -07:00
public bool AltDragOver(Vector2 screenSpaceMousePosition)
2015-04-08 15:20:10 -07:00
{
if (this.HasBeenClosed || this.DragDropSource == null)
2017-03-15 16:17:06 -07:00
{
return false;
}
bool itemAddedToScene = false;
var meshViewerPosition = this.meshViewerWidget.TransformToScreenSpace(meshViewerWidget.LocalBounds);
// If the mouse is within this control
if (meshViewerPosition.Contains(screenSpaceMousePosition)
&& this.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);
2017-06-16 11:12:24 -07:00
DragDropSource.Matrix *= Matrix4X4.CreateTranslation(new Vector3(intersectInfo.HitPosition));
2017-03-15 16:17:06 -07:00
2017-06-16 11:12:24 -07:00
CurrentSelectInfo.PlaneDownHitPos = intersectInfo.HitPosition;
2017-03-15 16:17:06 -07:00
CurrentSelectInfo.LastMoveDelta = Vector3.Zero;
2017-04-05 19:03:04 -07:00
this.deferEditorTillMouseUp = true;
2017-03-15 16:17:06 -07:00
// Add item to scene and select it
Scene.ModifyChildren(children =>
{
children.Add(DragDropSource);
});
2017-08-22 15:55:52 -07:00
Scene.SelectedItem = DragDropSource;
2017-03-15 16:17:06 -07:00
itemAddedToScene = true;
}
// Move the object being dragged
2017-03-15 16:17:06 -07:00
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
}
internal void FinishDrop()
{
this.DragDropSource = null;
this.DragSourceModel = null;
this.deferEditorTillMouseUp = false;
Scene_SelectionChanged(null, null);
this.PartHasBeenChanged();
// Set focus to View3DWidget after drag-drop
UiThread.RunOnIdle(this.Focus);
}
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(ListViewItem sourceListItem)
2017-03-15 16:17:06 -07:00
{
// Hold initial reference
IObject3D dragDropItem = DragDropSource;
if (dragDropItem == null)
2017-03-15 16:17:06 -07:00
{
return;
}
this.DragSourceModel = sourceListItem?.Model as ILibraryContentStream;
IObject3D loadedItem = await Task.Run(async () =>
2017-03-15 16:17:06 -07:00
{
if (File.Exists(dragDropItem.MeshPath))
2017-04-05 19:03:04 -07:00
{
string extensionWithoutPeriod = Path.GetExtension(dragDropItem.MeshPath).Trim('.');
if (ApplicationController.Instance.Library.ContentProviders.ContainsKey(extensionWithoutPeriod))
{
return null;
}
else
{
return Object3D.Load(dragDropItem.MeshPath, CancellationToken.None, progress: new DragDropLoadProgress(this, dragDropItem).ProgressReporter);
}
2017-04-05 19:03:04 -07:00
}
else if (DragSourceModel != null)
2017-04-05 19:03:04 -07:00
{
var loadProgress = new DragDropLoadProgress(this, dragDropItem);
ContentResult contentResult;
if (sourceListItem == null)
{
contentResult = DragSourceModel.CreateContent(loadProgress.ProgressReporter);
await contentResult.MeshLoaded;
}
else
{
sourceListItem.StartProgress();
contentResult = DragSourceModel.CreateContent((double ratio, string state) =>
{
sourceListItem.ProgressReporter(ratio, state);
loadProgress.ProgressReporter(ratio, state);
});
await contentResult.MeshLoaded;
sourceListItem.EndProgress();
loadProgress.ProgressReporter(1, "");
}
return contentResult?.Object3D;
2017-04-05 19:03:04 -07:00
}
return null;
2017-03-15 16:17:06 -07:00
});
if (loadedItem != null)
{
Vector3 meshGroupCenter = loadedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity).Center;
dragDropItem.Mesh = loadedItem.Mesh;
dragDropItem.Children = loadedItem.Children;
// TODO: jlewin - also need to apply the translation to the scale/rotation from the source (loadedItem.Matrix)
dragDropItem.Matrix = loadedItem.Matrix * dragDropItem.Matrix;
dragDropItem.Matrix *= Matrix4X4.CreateTranslation(-meshGroupCenter.x, -meshGroupCenter.y, -dragDropItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity).minXYZ.z);
2017-03-15 16:17:06 -07:00
}
this.PartHasBeenChanged();
2017-03-15 16:17:06 -07:00
}
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 this.InteractionLayer.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;
2015-05-30 12:48:16 -07:00
base.OnDraw(graphics2D);
}
2015-04-08 15:20:10 -07:00
private void AfterDraw3DContent(object sender, DrawEventArgs e)
{
if (DragSelectionInProgress)
{
var selectionRectangle = new RectangleDouble(DragSelectionStartPosition, DragSelectionEndPosition);
e.graphics2D.Rectangle(selectionRectangle, RGBA_Bytes.Red);
}
}
bool foundTriangleInSelectionBounds;
2017-06-06 10:57:13 -07:00
private void DoRectangleSelection(DrawEventArgs e)
{
var allResults = new List<BvhIterator>();
2017-06-06 10:57:13 -07:00
var matchingSceneChildren = Scene.Children.Where(item =>
{
foundTriangleInSelectionBounds = false;
2017-06-06 10:57:13 -07:00
// Filter the IPrimitive trace data finding matches as defined in InSelectionBounds
var filteredResults = item.TraceData().Filter(InSelectionBounds);
2017-06-06 10:57:13 -07:00
// Accumulate all matching BvhIterator results for debug rendering
allResults.AddRange(filteredResults);
return foundTriangleInSelectionBounds;
});
2017-06-06 10:57:13 -07:00
// Apply selection
if (matchingSceneChildren.Any())
{
2017-06-21 15:56:25 -07:00
// If we are actually doing the selection rather than debugging the data
if (e == null)
{
Scene.ClearSelection();
2017-08-22 15:55:52 -07:00
foreach (var sceneItem in matchingSceneChildren.ToList())
2017-06-21 15:56:25 -07:00
{
Scene.AddToSelection(sceneItem);
}
}
else
{
2017-06-21 15:56:25 -07:00
RenderBounds(e, allResults);
}
}
}
private bool InSelectionBounds(BvhIterator x)
{
var selectionRectangle = new RectangleDouble(DragSelectionStartPosition, DragSelectionEndPosition);
Vector2[] traceBottoms = new Vector2[4];
Vector2[] traceTops = new Vector2[4];
if (foundTriangleInSelectionBounds)
{
return false;
}
if (x.Bvh is TriangleShape tri)
{
// check if any vertex in screen rect
// calculate all the top and bottom screen positions
for (int i = 0; i < 3; i++)
{
Vector3 bottomStartPosition = Vector3.Transform(tri.GetVertex(i), x.TransformToWorld);
2017-07-10 14:00:27 -07:00
traceBottoms[i] = this.World.GetScreenPosition(bottomStartPosition);
}
for (int i = 0; i < 3; i++)
{
if (selectionRectangle.ClipLine(traceBottoms[i], traceBottoms[(i + 1) % 3]))
{
foundTriangleInSelectionBounds = true;
return true;
}
}
}
else
{
// calculate all the top and bottom screen positions
for (int i = 0; i < 4; i++)
{
Vector3 bottomStartPosition = Vector3.Transform(x.Bvh.GetAxisAlignedBoundingBox().GetBottomCorner(i), x.TransformToWorld);
2017-07-10 14:00:27 -07:00
traceBottoms[i] = this.World.GetScreenPosition(bottomStartPosition);
Vector3 topStartPosition = Vector3.Transform(x.Bvh.GetAxisAlignedBoundingBox().GetTopCorner(i), x.TransformToWorld);
2017-07-10 14:00:27 -07:00
traceTops[i] = this.World.GetScreenPosition(topStartPosition);
}
RectangleDouble.OutCode allPoints = RectangleDouble.OutCode.Inside;
// check if we are inside all the points
for (int i = 0; i < 4; i++)
{
allPoints |= selectionRectangle.ComputeOutCode(traceBottoms[i]);
allPoints |= selectionRectangle.ComputeOutCode(traceTops[i]);
}
if (allPoints == RectangleDouble.OutCode.Surrounded)
{
return true;
}
for (int i = 0; i < 4; i++)
{
if (selectionRectangle.ClipLine(traceBottoms[i], traceBottoms[(i + 1) % 4])
|| selectionRectangle.ClipLine(traceTops[i], traceTops[(i + 1) % 4])
|| selectionRectangle.ClipLine(traceTops[i], traceBottoms[i]))
{
return true;
}
}
}
return false;
}
private void RenderBounds(DrawEventArgs e, IEnumerable<BvhIterator> allResults)
{
foreach (var x in allResults)
{
for (int i = 0; i < 4; i++)
{
Vector3 bottomStartPosition = Vector3.Transform(x.Bvh.GetAxisAlignedBoundingBox().GetBottomCorner(i), x.TransformToWorld);
2017-07-10 14:00:27 -07:00
var bottomStartScreenPos = this.World.GetScreenPosition(bottomStartPosition);
Vector3 bottomEndPosition = Vector3.Transform(x.Bvh.GetAxisAlignedBoundingBox().GetBottomCorner((i + 1) % 4), x.TransformToWorld);
2017-07-10 14:00:27 -07:00
var bottomEndScreenPos = this.World.GetScreenPosition(bottomEndPosition);
Vector3 topStartPosition = Vector3.Transform(x.Bvh.GetAxisAlignedBoundingBox().GetTopCorner(i), x.TransformToWorld);
2017-07-10 14:00:27 -07:00
var topStartScreenPos = this.World.GetScreenPosition(topStartPosition);
Vector3 topEndPosition = Vector3.Transform(x.Bvh.GetAxisAlignedBoundingBox().GetTopCorner((i + 1) % 4), x.TransformToWorld);
2017-07-10 14:00:27 -07:00
var topEndScreenPos = this.World.GetScreenPosition(topEndPosition);
e.graphics2D.Line(bottomStartScreenPos, bottomEndScreenPos, RGBA_Bytes.Black);
e.graphics2D.Line(topStartScreenPos, topEndScreenPos, RGBA_Bytes.Black);
e.graphics2D.Line(topStartScreenPos, bottomStartScreenPos, RGBA_Bytes.Black);
}
TriangleShape tri = x.Bvh as TriangleShape;
if (tri != null)
{
for (int i = 0; i < 3; i++)
{
var vertexPos = tri.GetVertex(i);
var screenCenter = Vector3.Transform(vertexPos, x.TransformToWorld);
2017-07-10 14:00:27 -07:00
var screenPos = this.World.GetScreenPosition(screenCenter);
e.graphics2D.Circle(screenPos, 3, RGBA_Bytes.Red);
}
}
else
{
var center = x.Bvh.GetCenter();
var worldCenter = Vector3.Transform(center, x.TransformToWorld);
2017-07-10 14:00:27 -07:00
var screenPos2 = this.World.GetScreenPosition(worldCenter);
e.graphics2D.Circle(screenPos2, 3, RGBA_Bytes.Yellow);
e.graphics2D.DrawString($"{x.Depth},", screenPos2.x + 12 * x.Depth, screenPos2.y);
}
}
}
private void RendereSceneTraceData(DrawEventArgs e)
{
var bvhIterator = new BvhIterator(Scene?.TraceData(), decentFilter: (x) =>
{
var center = x.Bvh.GetCenter();
var worldCenter = Vector3.Transform(center, x.TransformToWorld);
if (worldCenter.z > 0)
{
return true;
}
return false;
});
RenderBounds(e, bvhIterator);
}
private ViewControls3DButtons? activeButtonBeforeMouseOverride = null;
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
2017-07-10 14:00:27 -07:00
if (this.TrackballTumbleWidget.UnderMouseState == 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 || ModifierKeys == Keys.Control)
|| (
2017-07-10 14:00:27 -07:00
this.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None
&& ModifierKeys != Keys.Control
&& ModifierKeys != Keys.Alt))
2015-04-08 15:20:10 -07:00
{
if (!this.InteractionLayer.MouseDownOnInteractionVolume)
2015-05-30 12:48:16 -07:00
{
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)
{
if (Scene.HasSelection)
{
2017-08-22 15:55:52 -07:00
Scene.ClearSelection();
SelectedTransformChanged?.Invoke(this, null);
}
// start a selection rect
DragSelectionStartPosition = mouseEvent.Position - OffsetToMeshViewerWidget();
DragSelectionEndPosition = DragSelectionStartPosition;
DragSelectionInProgress = true;
}
else
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
2017-08-22 15:55:52 -07:00
Scene.SelectedItem = hitObject;
2017-03-15 16:17:06 -07:00
}
else if ((ModifierKeys == Keys.Shift || ModifierKeys == Keys.Control)
&& !Scene.SelectedItem.Children.Contains(hitObject))
2017-03-15 16:17:06 -07:00
{
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)
{
2017-08-22 15:55:52 -07:00
Scene.SelectedItem = hitObject;
2017-03-15 16:17:06 -07:00
}
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;
AxisAlignedBoundingBox selectedBounds = this.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
2016-02-19 08:29:49 -08:00
2017-06-16 11:12:24 -07:00
if (info.HitPosition.x < selectedBounds.Center.x)
2016-02-19 08:29:49 -08:00
{
2017-06-16 11:12:24 -07:00
if (info.HitPosition.y < selectedBounds.Center.y)
2016-02-19 08:29:49 -08:00
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.LB;
}
else
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.LT;
}
}
else
{
2017-06-16 11:12:24 -07:00
if (info.HitPosition.y < selectedBounds.Center.y)
2016-02-19 08:29:49 -08:00
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.RB;
}
else
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.RT;
}
}
2017-03-15 16:17:06 -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 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);
2017-07-10 14:00:27 -07:00
Ray ray = this.World.GetRayForLocalBounds(localPosition);
2017-03-15 16:17:06 -07:00
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);
2017-07-10 14:00:27 -07:00
Ray ray = this.World.GetRayForLocalBounds(meshViewerWidgetScreenPosition);
2017-03-15 16:17:06 -07:00
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;
}
2017-06-16 11:12:24 -07:00
Vector3 delta = info.HitPosition - CurrentSelectInfo.PlaneDownHitPos;
2017-03-15 16:17:06 -07:00
double snapGridDistance = this.InteractionLayer.SnapGridDistance;
2017-03-15 16:17:06 -07:00
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 = this.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
2017-03-15 16:17:06 -07:00
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;
}
// if the shift key is down only move on the major axis of x or y
if(Keyboard.IsKeyDown(Keys.ShiftKey))
{
if(Math.Abs(delta.x) < Math.Abs(delta.y))
{
delta.x = 0;
}
else
{
delta.y = 0;
}
}
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 (AllowDragDrop() && mouseEvent.DragFiles?.Count == 1)
{
var screenSpaceMousePosition = this.TransformToScreenSpace(new Vector2(mouseEvent.X, mouseEvent.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))
{
this.DragDropSource.MeshPath = mouseEvent.DragFiles.FirstOrDefault();
// Run the rest of the OnDragOver pipeline since we're starting a new thread and won't finish for an unknown time
base.OnMouseMove(mouseEvent);
LoadDragSource(null);
// Don't fall through to the base.OnDragOver because we preemptively invoked it above
return;
}
}
// AcceptDrop anytime a DropSource has been queued
mouseEvent.AcceptDrop = this.DragDropSource != null;
2017-07-10 14:00:27 -07:00
if (CurrentSelectInfo.DownOnPart && this.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None)
2017-03-15 16:17:06 -07:00
{
DragSelectedObject(new Vector2(mouseEvent.X, mouseEvent.Y));
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
if (DragSelectionInProgress)
{
DragSelectionEndPosition = mouseEvent.Position - OffsetToMeshViewerWidget();
2017-06-30 18:33:49 -07:00
DragSelectionEndPosition = new Vector2(
Math.Max(Math.Min(DragSelectionEndPosition.x, meshViewerWidget.LocalBounds.Right), meshViewerWidget.LocalBounds.Left),
Math.Max(Math.Min(DragSelectionEndPosition.y, meshViewerWidget.LocalBounds.Top), meshViewerWidget.LocalBounds.Bottom));
Invalidate();
}
2015-05-30 12:48:16 -07:00
base.OnMouseMove(mouseEvent);
2015-04-08 15:20:10 -07:00
}
Vector2 OffsetToMeshViewerWidget()
{
List<GuiWidget> parents = new List<GuiWidget>();
GuiWidget parent = meshViewerWidget.Parent;
while (parent != this)
{
parents.Add(parent);
parent = parent.Parent;
}
Vector2 offset = new Vector2();
for(int i=parents.Count-1; i>=0; i--)
{
offset += parents[i].OriginRelativeParent;
}
return offset;
}
2017-07-10 14:00:27 -07:00
public void ResetView()
{
this.TrackballTumbleWidget.ZeroVelocity();
var world = this.World;
world.Reset();
world.Scale = .03;
2017-08-16 05:55:23 -07:00
world.Translate(-new Vector3(printer.Bed.BedCenter));
2017-07-10 14:00:27 -07:00
world.Rotate(Quaternion.FromEulerAngles(new Vector3(0, 0, MathHelper.Tau / 16)));
world.Rotate(Quaternion.FromEulerAngles(new Vector3(-MathHelper.Tau * .19, 0, 0)));
}
2015-05-30 12:48:16 -07:00
public override void OnMouseUp(MouseEventArgs mouseEvent)
2015-04-08 15:20:10 -07:00
{
if (mouseEvent.DragFiles?.Count > 0)
{
if (AllowDragDrop() && mouseEvent.DragFiles.Count == 1)
{
// Item is already in the scene
this.DragDropSource = null;
}
else if (AllowDragDrop())
{
// Items need to be added to the scene
var partsToAdd = mouseEvent.DragFiles.Where(filePath => ApplicationController.Instance.IsLoadableFile(filePath)).ToArray();
if (partsToAdd.Length > 0)
{
loadAndAddPartsToPlate(partsToAdd);
}
}
}
2017-07-10 14:00:27 -07:00
if (this.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None)
2015-04-08 15:20:10 -07:00
{
2017-07-11 12:50:21 -07:00
if (Scene.SelectedItem != null
&& CurrentSelectInfo.DownOnPart
&& CurrentSelectInfo.LastMoveDelta != Vector3.Zero)
{
InteractionLayer.AddTransformSnapshot(transformOnMouseDown);
}
else if (DragSelectionInProgress)
{
2017-06-06 10:57:13 -07:00
DoRectangleSelection(null);
DragSelectionInProgress = false;
}
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);
if (deferEditorTillMouseUp)
{
this.deferEditorTillMouseUp = false;
Scene_SelectionChanged(null, 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
public void PartHasBeenChanged()
{
partHasBeenEdited = true;
SelectedTransformChanged?.Invoke(this, null);
2016-02-27 15:01:28 -08:00
Invalidate();
2015-04-08 15:20:10 -07:00
}
internal GuiWidget AddAlignControls()
{
var widget = new IgnoredPopupWidget()
{
HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Fit,
BackgroundColor = RGBA_Bytes.White,
2017-08-17 15:21:29 -07:00
Padding = new BorderDouble(5, 5, 5, 0)
};
FlowLayoutWidget buttonPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.Fit,
HAnchor = HAnchor.Fit,
};
widget.AddChild(buttonPanel);
string[] axisNames = new string[] { "X", "Y", "Z" };
for (int axisIndex = 0; axisIndex < 3; axisIndex++)
{
FlowLayoutWidget alignButtons = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Fit,
Padding = new BorderDouble(5)
};
buttonPanel.AddChild(alignButtons);
alignButtons.AddChild(new TextWidget(axisNames[axisIndex])
2017-08-17 15:21:29 -07:00
{
VAnchor = VAnchor.Center,
Margin = new BorderDouble(0, 0, 3, 0)
});
2017-08-17 15:21:29 -07:00
alignButtons.AddChild(CreateAlignButton(axisIndex, AxisAlignment.Min, "Min"));
alignButtons.AddChild(new HorizontalSpacer());
2017-08-17 15:21:29 -07:00
alignButtons.AddChild(CreateAlignButton(axisIndex, AxisAlignment.Center, "Center"));
alignButtons.AddChild(new HorizontalSpacer());
2017-08-17 15:21:29 -07:00
alignButtons.AddChild(CreateAlignButton(axisIndex, AxisAlignment.Max, "Max"));
alignButtons.AddChild(new HorizontalSpacer());
}
return widget;
}
2017-08-17 15:21:29 -07:00
internal enum AxisAlignment { Min, Center, Max };
private GuiWidget CreateAlignButton(int axisIndex, AxisAlignment alignment, string lable)
{
var smallMarginButtonFactory = ApplicationController.Instance.Theme.MenuButtonFactory;
2017-08-17 15:21:29 -07:00
var alignButton = smallMarginButtonFactory.Generate(lable);
alignButton.Margin = new BorderDouble(3, 0);
int extruderIndexCanPassToClick = axisIndex;
alignButton.Click += (sender, e) =>
{
if (Scene.HasSelection)
{
2017-08-22 15:55:52 -07:00
var transformDatas = GetTransforms(axisIndex, alignment);
2017-08-17 15:21:29 -07:00
2017-08-22 15:55:52 -07:00
this.Scene.UndoBuffer.AddAndDo(new TransformUndoCommand(transformDatas));
2017-08-17 15:21:29 -07:00
//Scene.SelectedItem.MaterialIndex = extruderIndexCanPassToClick;
PartHasBeenChanged();
}
};
alignButton.MouseEnter += (s2, e2) =>
{
2017-08-22 15:55:52 -07:00
// make a preview of the new positions
var transformDatas = GetTransforms(axisIndex, alignment);
foreach (var transform in transformDatas)
{
var copy = transform.TransformedObject.Clone();
copy.Matrix = transform.RedoTransform;
copy.Color = new RGBA_Bytes(copy.Color, 126);
Scene.Children.Add(copy);
}
};
alignButton.MouseLeave += (s3, e3) =>
{
2017-08-22 15:55:52 -07:00
// clear the preview of the new positions
foreach(var child in Scene.Children.ToArray())
{
if(child.Color.Alpha0To255 == 126)
{
Scene.Children.Remove(child);
}
}
};
return alignButton;
}
2017-08-22 15:55:52 -07:00
private List<TransformData> GetTransforms(int axisIndex, AxisAlignment alignment)
{
var transformDatas = new List<TransformData>();
var totalAABB = Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
// move the objects to the right place
foreach (var child in Scene.SelectedItem.Children)
{
var childAABB = child.GetAxisAlignedBoundingBox(Scene.SelectedItem.Matrix);
var offset = new Vector3();
switch (alignment)
{
case AxisAlignment.Min:
offset[axisIndex] = totalAABB.minXYZ[axisIndex] - childAABB.minXYZ[axisIndex];
break;
case AxisAlignment.Center:
offset[axisIndex] = totalAABB.Center[axisIndex] - childAABB.Center[axisIndex];
break;
case AxisAlignment.Max:
{
offset[axisIndex] = totalAABB.maxXYZ[axisIndex] - childAABB.maxXYZ[axisIndex];
}
break;
}
transformDatas.Add(new TransformData()
{
TransformedObject = child,
RedoTransform = child.Matrix * Matrix4X4.CreateTranslation(offset),
UndoTransform = child.Matrix,
});
}
return transformDatas;
}
internal GuiWidget AddMaterialControls()
2015-04-08 15:20:10 -07:00
{
var widget = new IgnoredPopupWidget()
{
HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Fit,
BackgroundColor = RGBA_Bytes.White,
Padding = new BorderDouble(0, 5, 5, 0)
};
FlowLayoutWidget buttonPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.Fit,
HAnchor = HAnchor.Fit,
};
widget.AddChild(buttonPanel);
2015-05-30 12:48:16 -07:00
extruderButtons.Clear();
2017-08-01 17:38:07 -07:00
int extruderCount = 4;
for (int extruderIndex = 0; extruderIndex < extruderCount; extruderIndex++)
2015-04-08 15:20:10 -07:00
{
2017-08-10 12:55:24 -07:00
FlowLayoutWidget colorSelectionContainer = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Fit,
Padding = new BorderDouble(5)
};
buttonPanel.AddChild(colorSelectionContainer);
2015-05-30 12:48:16 -07:00
2017-09-08 17:13:06 -07:00
string materialLabelText = string.Format("{0} {1}", "Material".Localize(), extruderIndex + 1);
2016-04-18 11:31:31 -07:00
2017-09-08 17:13:06 -07:00
RadioButton materialSelection = new RadioButton(materialLabelText, textColor: RGBA_Bytes.Black);
extruderButtons.Add(materialSelection);
materialSelection.SiblingRadioButtonList = extruderButtons;
colorSelectionContainer.AddChild(materialSelection);
2015-05-30 12:48:16 -07:00
colorSelectionContainer.AddChild(new HorizontalSpacer());
int extruderIndexCanPassToClick = extruderIndex;
2017-09-08 17:13:06 -07:00
materialSelection.Click += (sender, e) =>
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
{
2017-08-01 17:38:07 -07:00
Scene.SelectedItem.MaterialIndex = extruderIndexCanPassToClick;
PartHasBeenChanged();
2017-09-08 17:13:06 -07:00
// "View 3D Overflow Menu" // the menu to click on
// "Materials Option" // the item to highlight
//HelpSystem.
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
};
2014-10-13 19:29:25 -07:00
2017-08-10 12:55:24 -07:00
colorSelectionContainer.AddChild(new GuiWidget(16, 16)
{
2017-08-10 18:04:36 -07:00
BackgroundColor = MatterialRendering.Color(extruderIndex),
Margin = new BorderDouble(5, 0, 0, 0)
2017-08-10 12:55:24 -07:00
});
2015-04-08 15:20:10 -07:00
}
return widget;
2015-04-08 15:20:10 -07:00
}
// Indicates if MatterControl is in a mode that allows DragDrop - true if printItem not null and not ReadOnly
private bool AllowDragDrop() => !printItemWrapper?.PrintItem.ReadOnly ?? false;
2015-05-30 12:48:16 -07:00
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 = this.World.RotationMatrix.GetRotation();
2015-05-30 12:48:16 -07:00
Quaternion invertedRotation = Quaternion.Invert(currentRotation);
Quaternion rotateAboutZ = Quaternion.FromEulerAngles(new Vector3(0, 0, .01));
rotateAboutZ = invertedRotation * rotateAboutZ * currentRotation;
2017-07-10 14:00:27 -07:00
this.World.Rotate(rotateAboutZ);
2015-05-30 12:48:16 -07:00
Invalidate();
}
}
}
internal void ReportProgressChanged(double progress0To1, string processingState)
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();
}
}
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
{
SwitchStateToEditing();
2017-03-15 16:17:06 -07:00
Scene.ModifyChildren(children => children.Clear());
if (newPrintItem != null)
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();
await meshViewerWidget.LoadItemIntoScene(newPrintItem.FileLocation, bedCenter, newPrintItem.Name);
2017-03-15 16:17:06 -07:00
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
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
public IObject3DEditor ActiveSelectionEditor { get; set; }
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-04-05 19:03:04 -07:00
if (deferEditorTillMouseUp)
{
return;
}
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
if (mappedEditors == null)
2017-03-15 16:17:06 -07:00
{
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
// Add any editor mapped to Object3D to the list
if (objectEditorsByType.TryGetValue(typeof(Object3D), out HashSet<IObject3DEditor> globalEditors))
{
foreach(var editor in globalEditors)
{
mappedEditors.Add(editor);
}
}
2017-03-15 16:17:06 -07:00
editorPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.Fit,
2017-03-15 16:17:06 -07:00
};
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 = 3
2017-03-15 16:17:06 -07:00
};
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
this.ActiveSelectionEditor = (from editor in mappedEditors
let type = editor.GetType()
where type.Name == selectedItem.ActiveEditor
select editor).FirstOrDefault();
2015-05-30 12:48:16 -07:00
// Fall back to default editor?
if (this.ActiveSelectionEditor == null)
2015-05-30 12:48:16 -07:00
{
this.ActiveSelectionEditor = mappedEditors.First();
2017-03-15 16:17:06 -07:00
}
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++)
2017-03-15 16:17:06 -07:00
{
if (dropDownList.MenuItems[i].Text == this.ActiveSelectionEditor.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
ShowObjectEditor(this.ActiveSelectionEditor);
2015-05-30 12:48:16 -07:00
}
if (extruderButtons?.Count > 0)
{
bool setSelection = false;
// Set the material selector to have the correct material button selected
for (int i = 0; i < extruderButtons.Count; i++)
{
2017-08-01 17:38:07 -07:00
if (selectedItem.MaterialIndex == i)
{
((RadioButton)extruderButtons[i]).Checked = true;
setSelection = true;
}
}
if(!setSelection)
{
((RadioButton)extruderButtons[0]).Checked = true;
}
}
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)
{
editorPanel.CloseAllChildren();
var newEditor = editor.Create(Scene.SelectedItem, this, this.theme);
2017-03-15 16:17:06 -07:00
editorPanel.AddChild(newEditor);
2015-05-30 12:48:16 -07: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-07-10 14:00:27 -07:00
Vector2 centerTopScreenPosition = this.World.GetScreenPosition(centerTop);
2017-03-15 16:17:06 -07:00
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
}
private async void LoadAndAddPartsToPlate(string[] filesToLoad)
2015-05-30 12:48:16 -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
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 filePath in filesToLoad)
2015-05-30 12:48:16 -07:00
{
var libraryItem = new FileSystemFileItem(filePath);
2017-04-05 19:03:04 -07:00
var contentResult = libraryItem.CreateContent((double progress0To1, string processingState) =>
2015-05-30 12:48:16 -07:00
{
double ratioAvailable = (ratioPerFile * .5);
double currentRatio = currentRatioDone + progress0To1 * ratioAvailable;
ReportProgressChanged(currentRatio, progressMessage);
});
contentResult?.MeshLoaded.ContinueWith((task) =>
2017-04-05 19:03:04 -07:00
{
if (contentResult != null && contentResult.Object3D != null)
2017-04-05 19:03:04 -07:00
{
Scene.ModifyChildren(children => children.Add(contentResult.Object3D));
PlatingHelper.MoveToOpenPosition(contentResult.Object3D, this.Scene.Children);
// TODO: There should be a batch insert so you can undo large 'add to scene' operations in one go
//this.InsertNewItem(tempScene);
}
});
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
2015-05-30 12:48:16 -07:00
currentRatioDone += ratioPerFile;
}
}
this.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
public void LockEditControls()
2015-05-30 12:48:16 -07:00
{
2017-08-07 07:37:47 -07:00
viewIsInEditModePreLock = selectionActionBar.Visible;
selectionActionBar.Visible = false;
2015-04-08 15:20:10 -07:00
}
2014-01-29 19:09:30 -08:00
internal void MakeLowestFaceFlat(IObject3D objectToLayFlatGroup)
2015-04-08 15:20:10 -07:00
{
bool firstVertex = true;
2017-03-15 16:17:06 -07:00
Matrix4X4 objectToWold = objectToLayFlatGroup.Matrix;
IObject3D objectToLayFlat = objectToLayFlatGroup;
IVertex lowestVertex = null;
Vector3 lowestVertexPosition = Vector3.Zero;
2017-03-15 16:17:06 -07:00
IObject3D itemToLayFlat = null;
// Process each child, checking for the lowest vertex
var objectsToCheck = objectToLayFlat.Children.Where(child => child.Mesh != null).ToList();
if(objectToLayFlat.Mesh != null)
{
objectsToCheck.Add(objectToLayFlat);
}
foreach (IObject3D itemToCheck in objectsToCheck)
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-07-18 20:51:32 -07:00
var vertex = itemToCheck.Mesh.Vertices[testIndex];
2017-03-15 16:17:06 -07:00
Vector3 vertexPosition = Vector3.Transform(vertex.Position, objectToWold);
if(firstVertex)
{
lowestVertex = itemToCheck.Mesh.Vertices[testIndex];
lowestVertexPosition = vertexPosition;
itemToLayFlat = itemToCheck;
firstVertex = false;
}
else if (vertexPosition.z < lowestVertexPosition.z)
2015-05-30 12:48:16 -07:00
{
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;
2017-07-18 18:20:04 -07:00
foreach (IVertex 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> faceVertices = new List<Vector3>();
2017-07-18 18:20:04 -07:00
foreach (IVertex 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);
faceVertices.Add(vertexPosition);
2015-05-30 12:48:16 -07:00
maxDistFromLowestZ = Math.Max(maxDistFromLowestZ, vertexPosition.z - lowestVertexPosition.z);
}
2015-05-30 12:48:16 -07:00
if (maxDistFromLowestZ > .001)
{
Vector3 xPositive = (faceVertices[1] - faceVertices[0]).GetNormal();
Vector3 yPositive = (faceVertices[2] - faceVertices[0]).GetNormal();
2015-05-30 12:48:16 -07:00
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();
}
2017-09-05 18:02:19 -07:00
PlatingHelper.PlaceOnBed(objectToLayFlatGroup);
2015-05-30 12:48:16 -07:00
}
public static Regex fileNameNumberMatch = new Regex("\\(\\d+\\)", RegexOptions.Compiled);
internal GuiWidget selectedObjectPanel;
2017-03-15 16:17:06 -07:00
private FlowLayoutWidget editorPanel;
2015-04-08 15:20:10 -07:00
private async Task SaveChanges()
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
{
// Force to .mcx
if (Path.GetExtension(printItemWrapper.FileLocation) != ".mcx")
{
printItemWrapper.FileLocation = Path.ChangeExtension(printItemWrapper.FileLocation, ".mcx");
2017-03-15 16:17:06 -07:00
}
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
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();
partHasBeenEdited = false;
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
{
if (printer.Bed.RendererOptions.SyncToPrint)
2015-05-30 12:48:16 -07:00
{
switch (printerConnection.CommunicationState)
2015-05-30 12:48:16 -07:00
{
case CommunicationStates.Printing:
case CommunicationStates.Paused:
2015-05-30 12:48:16 -07:00
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
}
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()
{
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;
}
2015-05-30 12:48:16 -07:00
private void OpenExportWindow()
{
var exportPage = new ExportPrintItemPage(new[] { new FileSystemFileItem(this.printItemWrapper.FileLocation) });
WizardWindow.Show(exportPage);
2015-05-30 12:48:16 -07:00
}
2014-01-29 19:09:30 -08:00
private void OpenSaveAsWindow()
2015-05-30 12:48:16 -07:00
{
if (saveAsWindow == null)
{
saveAsWindow = new SaveAsWindow(
async (returnInfo) =>
{
// TODO: The PrintItemWrapper seems unnecessary in the new LibraryContainer model. Couldn't we just pass the scene to the LibraryContainer via it's add function, no need to perist to disk?
// Create a new PrintItemWrapper
printItemWrapper = new PrintItemWrapper(
new PrintItem()
{
Name = returnInfo.newName,
FileLocation = Path.ChangeExtension(returnInfo.fileNameAndPath, ".mcx")
},
returnInfo.DestinationContainer);
// Save the scene to disk
await this.SaveChanges();
// Save to the destination provider
if (returnInfo?.DestinationContainer != null)
{
// save this part to correct library provider
if (returnInfo.DestinationContainer is ILibraryWritableContainer writableContainer)
{
writableContainer.Add(new[]
{
new FileSystemFileItem(printItemWrapper.FileLocation)
{
Name = returnInfo.newName
}
});
returnInfo.DestinationContainer.Dispose();
}
}
},
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 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 void SetEditControlsBasedOnPrinterState(object sender, EventArgs e)
2015-04-08 15:20:10 -07:00
{
if (printer.Bed.RendererOptions.SyncToPrint)
2015-04-08 15:20:10 -07:00
{
switch (printerConnection.CommunicationState)
2015-04-08 15:20:10 -07:00
{
case CommunicationStates.Printing:
case CommunicationStates.Paused:
2015-05-30 12:48:16 -07:00
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
}
}
}
public Vector2 DragSelectionStartPosition { get; private set; }
public bool DragSelectionInProgress { get; private set; }
public Vector2 DragSelectionEndPosition { get; private set; }
2017-03-15 16:17:06 -07:00
internal async void SwitchStateToEditing()
{
viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect;
processingProgressControl.Visible = true;
LockEditControls();
viewIsInEditModePreLock = true;
if (Scene.HasChildren())
2017-03-15 16:17:06 -07:00
{
// 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", continueProcessing2);
2017-03-15 16:17:06 -07:00
//meshViewerWidget.CreateGlDataForMeshes(Scene.Children);
});
if (this.HasBeenClosed)
{
return;
}
Scene.SelectFirstChild();
}
UnlockEditControls();
viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect;
Invalidate();
}
// Before printing persist any changes to disk
internal async Task PersistPlateIfNeeded()
{
if (partHasBeenEdited)
{
await this.SaveChanges();
}
}
2017-03-15 16:17:06 -07:00
public void UnlockEditControls()
2015-05-30 12:48:16 -07:00
{
processingProgressControl.Visible = false;
if (viewIsInEditModePreLock)
2015-04-08 15:20:10 -07:00
{
viewControls3D.PartSelectVisible = true;
2017-08-07 07:37:47 -07:00
selectionActionBar.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
}
internal GuiWidget ShowOverflowMenu()
{
var popupContainer = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
Padding = 12,
BackgroundColor = RGBA_Bytes.White
};
var meshViewer = meshViewerWidget;
popupContainer.AddChild(
2017-07-05 14:47:52 -07:00
this.theme.CreateCheckboxMenuItem(
"Show Print Bed".Localize(),
2017-07-05 15:00:53 -07:00
"ShowPrintBed",
meshViewer.RenderBed,
5,
(s, e) =>
{
if (s is CheckBox checkbox)
{
meshViewer.RenderBed = checkbox.Checked;
}
}));
double buildHeight = ActiveSliceSettings.Instance.GetValue<double>(SettingsKey.build_height);
if (buildHeight > 0)
{
popupContainer.AddChild(
2017-07-05 14:47:52 -07:00
this.theme.CreateCheckboxMenuItem(
"Show Print Area".Localize(),
2017-07-05 15:00:53 -07:00
"ShowPrintArea",
2017-07-05 15:04:17 -07:00
meshViewer.RenderBuildVolume,
5,
(s, e) =>
{
if (s is CheckBox checkbox)
{
meshViewer.RenderBuildVolume = checkbox.Checked;
}
}));
}
popupContainer.AddChild(new HorizontalLine());
var renderOptions = CreateRenderTypeRadioButtons();
popupContainer.AddChild(renderOptions);
popupContainer.AddChild(new GridOptionsPanel(this.InteractionLayer));
return popupContainer;
}
private GuiWidget CreateRenderTypeRadioButtons()
{
var container = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
HAnchor = HAnchor.Stretch,
Margin = new BorderDouble(5, 5, 5, 0)
};
string renderTypeString = UserSettings.Instance.get(UserSettingsKey.defaultRenderSetting);
if (renderTypeString == null)
{
if (UserSettings.Instance.IsTouchScreen)
{
renderTypeString = "Shaded";
}
else
{
renderTypeString = "Outlines";
}
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, renderTypeString);
}
//var itemTextColor = ActiveTheme.Instance.PrimaryTextColor;
var itemTextColor = RGBA_Bytes.Black;
RenderTypes renderType;
bool canParse = Enum.TryParse(renderTypeString, out renderType);
if (canParse)
{
meshViewerWidget.RenderType = renderType;
}
{
RadioButton renderTypeCheckBox = new RadioButton("Shaded".Localize(), textColor: itemTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Shaded);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
{
if (renderTypeCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Shaded;
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString());
}
};
container.AddChild(renderTypeCheckBox);
}
{
RadioButton renderTypeCheckBox = new RadioButton("Outlines".Localize(), textColor: itemTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Outlines);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
{
if (renderTypeCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Outlines;
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString());
}
};
container.AddChild(renderTypeCheckBox);
}
{
RadioButton renderTypeCheckBox = new RadioButton("Polygons".Localize(), textColor: itemTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Polygons);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
{
if (renderTypeCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Polygons;
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString());
}
};
container.AddChild(renderTypeCheckBox);
}
2017-08-01 17:38:07 -07:00
// Materials option
{
RadioButton materialsCheckBox = new RadioButton("Materials".Localize(), textColor: itemTextColor);
2017-09-08 17:13:06 -07:00
materialsCheckBox.Name = "Materials Option";
2017-08-01 17:38:07 -07:00
materialsCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Materials);
materialsCheckBox.CheckedStateChanged += (sender, e) =>
{
if (materialsCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Materials;
UserSettings.Instance.set("defaultRenderSetting", meshViewerWidget.RenderType.ToString());
}
};
container.AddChild(materialsCheckBox);
}
// overhang setting
{
RadioButton renderTypeCheckBox = new RadioButton("Overhang".Localize(), textColor: itemTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Overhang);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
{
if (renderTypeCheckBox.Checked)
{
// TODO: Determine if Scene is available in scope
var scene = this.Scene;
meshViewerWidget.RenderType = RenderTypes.Overhang;
UserSettings.Instance.set("defaultRenderSetting", meshViewerWidget.RenderType.ToString());
foreach (var meshRenderData in scene.VisibleMeshes())
{
2017-08-01 17:38:07 -07:00
meshRenderData.Mesh.MarkAsChanged();
// change the color to be the right thing
2017-08-01 17:38:07 -07:00
GLMeshTrianglePlugin glMeshPlugin = GLMeshTrianglePlugin.Get(meshRenderData.Mesh, (faceEdge) =>
{
2017-08-23 17:51:38 -07:00
Vector3 normal = faceEdge.ContainingFace.Normal;
2017-08-01 17:38:07 -07:00
normal = Vector3.TransformVector(normal, meshRenderData.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;
});
}
}
};
container.AddChild(renderTypeCheckBox);
}
2017-08-01 17:38:07 -07:00
return container;
}
protected bool autoRotating = false;
protected bool allowAutoRotate = false;
public MeshViewerWidget meshViewerWidget;
public InteractiveScene Scene { get; }
protected ViewControls3D viewControls3D { get; }
public MeshSelectInfo CurrentSelectInfo { get; } = new MeshSelectInfo();
protected IObject3D FindHitObject3D(Vector2 screenPosition, ref IntersectInfo intersectionInfo)
{
Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, screenPosition);
2017-07-10 14:00:27 -07:00
Ray ray = this.World.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;
}
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
}
}