mattercontrol/PartPreviewWindow/View3D/View3DWidget.cs

2453 lines
71 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;
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.PrintLibrary;
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;
public DisableablePanel bottomActionPanel;
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
internal bool partHasBeenEdited = false;
private 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
2015-05-30 12:48:16 -07:00
private bool wasInSelectMode = false;
2015-04-08 15:20:10 -07:00
private ThemeConfig theme;
2017-09-05 18:02:19 -07:00
public Vector3 BedCenter
{
get
{
return new Vector3(sceneContext.BedCenter);
2017-09-05 18:02:19 -07:00
}
}
private WorldView World => sceneContext.World;
2017-07-10 14:00:27 -07:00
public TrackballTumbleWidget TrackballTumbleWidget { get; }
internal ViewGcodeBasic gcodeViewer;
public InteractionLayer InteractionLayer { get; }
private BedConfig sceneContext;
private PrinterConfig printer;
private PrinterTabBase printerTabBase;
public View3DWidget(PrinterConfig printer, BedConfig sceneContext, AutoRotate autoRotate, ViewControls3D viewControls3D, ThemeConfig theme, PrinterTabBase printerTabBase, MeshViewerWidget.EditorType editorType = MeshViewerWidget.EditorType.Part)
2015-05-30 12:48:16 -07:00
{
2017-08-18 08:34:05 -07:00
var smallMarginButtonFactory = theme.SmallMarginButtonFactory;
this.sceneContext = sceneContext;
this.printerTabBase = printerTabBase;
this.Scene = sceneContext.Scene;
this.printer = printer;
2017-07-10 14:00:27 -07:00
2017-09-16 01:19:35 -07:00
this.TrackballTumbleWidget = new TrackballTumbleWidget(sceneContext.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;
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(sceneContext, 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
2017-10-19 09:04:36 -07:00
gcodeViewer = new ViewGcodeBasic(printer, sceneContext, viewControls3D, theme);
2017-09-23 00:29:03 -07:00
gcodeViewer.Name = "ViewGcodeBasic";
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
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
{
var selectionActionBar = new FlowLayoutWidget()
2017-08-12 00:40:03 -07:00
{
VAnchor = VAnchor.Center | VAnchor.Fit,
HAnchor = HAnchor.Stretch
};
2017-08-07 07:41:30 -07:00
bottomActionPanel = new DisableablePanel(selectionActionBar, enabled: true);
processingProgressControl = new ProgressControl("", ActiveTheme.Instance.PrimaryTextColor, ActiveTheme.Instance.PrimaryAccentColor)
{
VAnchor = VAnchor.Top,
HAnchor = HAnchor.Center,
MinimumSize = new Vector2(400, 40),
BackgroundColor = theme.SlightShade,
Padding = 10
};
this.InteractionLayer.AddChild(processingProgressControl);
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, IconColor.Theme));
addButton.Margin = 0;
2017-08-07 07:41:30 -07:00
addButton.Click += (sender, e) =>
{
2017-09-27 07:20:35 -07:00
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),
2017-09-27 07:20:35 -07:00
(openParams) =>
2017-08-07 07:41:30 -07:00
{
2017-09-27 07:20:35 -07:00
this.LoadAndAddPartsToPlate(openParams.FileNames);
});
});
2017-08-07 07:41:30 -07:00
};
selectionActionBar.AddChild(addButton);
selectionActionBar.AddChild(this.CreateActionSeparator());
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
2017-10-13 15:00:08 -07:00
&& 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
2017-10-13 15:00:08 -07:00
&& 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);
selectionActionBar.AddChild(this.CreateActionSeparator());
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-09-16 01:11:44 -07:00
PopupContent = new MirrorControls(this, Scene),
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 (sceneContext.printItem == 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>());
}
},
2017-09-27 07:20:35 -07:00
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 = () =>
{
2017-09-15 18:45:21 -07:00
UiThread.RunOnIdle(sceneContext.ClearPlate);
2017-08-12 00:23:41 -07:00
}
}
2017-08-07 07:41:30 -07:00
};
2017-08-17 11:18:11 -07:00
bool isPrinterMode = meshViewerWidget.EditorMode == MeshViewerWidget.EditorType.Printer;
var buttonView = smallMarginButtonFactory.Generate(
label: (isPrinterMode) ? "Bed".Localize() : "Part".Localize(),
normalImage: AggContext.StaticData.LoadIcon((isPrinterMode) ? "bed.png" : "cube.png", IconColor.Theme));
2017-08-17 11:18:11 -07:00
selectionActionBar.AddChild(
new PopupButton(buttonView)
{
PopDirection = Direction.Up,
PopupContent = ApplicationController.Instance.Theme.CreatePopupMenu(bedMenuActions),
AlignToRightEdge = true,
Margin = buttonSpacing,
Name = "Bed Options Menu",
});
2017-06-27 18:41:34 -07:00
}
2017-06-26 17:19:27 -07:00
buttonBottomPanel.AddChild(bottomActionPanel);
2017-08-07 07:41:30 -07:00
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;
selectedObjectPanel = new SelectedObjectPanel(this, this.Scene, theme)
2017-03-15 16:17:06 -07:00
{
2017-10-19 09:04:36 -07:00
BackgroundColor = new RGBA_Bytes(0, 0, 0, theme.OverlayAlpha),
VAnchor = VAnchor.Top | VAnchor.Fit,
HAnchor = HAnchor.Left | HAnchor.Fit,
2017-03-15 16:17:06 -07:00
};
selectedObjectContainer = new ResizeContainer(selectedObjectPanel)
{
Width = 200,
VAnchor = VAnchor.Fit | VAnchor.Top,
HAnchor = HAnchor.Right,
Margin = new BorderDouble(0, 0, 0, viewControls3D.LocalBounds.Height),
SpliterBarColor = new RGBA_Bytes(RGBA_Bytes.Red, 30),
SplitterWidth = ApplicationController.Instance.Theme.SplitterWidth,
Visible = false,
};
this.AddChild(selectedObjectContainer);
selectedObjectContainer.AddChild(selectedObjectPanel);
2017-03-15 16:17:06 -07:00
2015-04-08 15:20:10 -07:00
UiThread.RunOnIdle(AutoSpin);
2014-05-27 09:16:35 -07:00
// Wire up CommunicationStateChanged to lock footer bar when SyncToPrint is enabled
if (sceneContext.Printer != null)
2015-04-08 15:20:10 -07:00
{
sceneContext.Printer.Connection.CommunicationStateChanged.RegisterEvent((s, e) =>
2015-04-08 15:20:10 -07:00
{
if (sceneContext.RendererOptions.SyncToPrint
&& sceneContext.Printer != null)
{
switch (sceneContext.Printer.Connection.CommunicationState)
{
case CommunicationStates.Printing:
case CommunicationStates.Paused:
LockEditControls();
break;
default:
UnlockEditControls();
break;
}
}
},
ref unregisterEvents);
// make sure we lock the controls if we are printing or paused
switch (sceneContext.Printer.Connection.CommunicationState)
{
case CommunicationStates.Printing:
case CommunicationStates.Paused:
if (sceneContext.RendererOptions.SyncToPrint)
{
LockEditControls();
}
break;
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;
sceneContext.LoadedGCodeChanged += SceneContext_LoadedGCodeChanged;
2017-09-15 23:17:03 -07:00
this.SwitchStateToEditing();
this.InteractionLayer.DrawGlOpaqueContent += Draw_GlOpaqueContent;
2017-03-15 16:17:06 -07:00
}
private void SceneContext_LoadedGCodeChanged(object sender, EventArgs e)
{
if (printerTabBase is PrinterTabPage printerTabPage)
{
// When GCode changes, switch to the 3D layer view
printerTabPage.ViewMode = PartViewMode.Layers3D;
// HACK: directly fire method which previously ran on SlicingDone event on PrintItemWrapper
UiThread.RunOnIdle(() => printerTabPage.view3DWidget.gcodeViewer.CreateAndAddChildren(printer));
}
}
private GuiWidget CreateActionSeparator()
{
return 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
private void Draw_GlOpaqueContent(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
if (sceneContext.LoadedGCode == null || sceneContext.GCodeRenderer == null || !gcodeViewer.Visible)
2017-07-10 14:00:27 -07:00
{
return;
}
sceneContext.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-10-13 15:00:08 -07:00
booleanGroup = new Object3D { ItemType = Object3DTypes.Group };
2017-03-15 16:17:06 -07:00
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-09-26 12:52:54 -07:00
this.Scene.Children.Modify(list =>
2017-03-15 16:17:06 -07:00
{
2017-09-26 12:52:54 -07:00
list.Add(booleanGroup);
2017-03-15 16:17:06 -07:00
});
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 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
{
viewControls3D.TransformStateChanged -= ViewControls3D_TransformStateChanged;
sceneContext.LoadedGCodeChanged -= SceneContext_LoadedGCodeChanged;
this.Scene.SelectionChanged -= Scene_SelectionChanged;
this.InteractionLayer.DrawGlOpaqueContent -= Draw_GlOpaqueContent;
if (meshViewerWidget != null)
{
meshViewerWidget.AfterDraw -= AfterDraw3DContent;
}
2017-03-15 16:17:06 -07:00
unregisterEvents?.Invoke(this, null);
base.OnClosed(e);
2015-05-30 12:48:16 -07:00
}
2017-09-16 01:11:44 -07:00
public override void OnVisibleChanged(EventArgs e)
{
var dragDropData = ApplicationController.Instance.DragDropData;
if (this.Visible)
{
// Set reference on show
dragDropData.View3DWidget = this;
2017-10-05 22:32:23 -07:00
dragDropData.SceneContext = sceneContext;
2017-09-16 01:11:44 -07:00
}
else
{
// Clear state on hide
if (dragDropData.View3DWidget == this)
{
dragDropData.Reset();
}
}
base.OnVisibleChanged(e);
}
2017-03-15 16:17:06 -07:00
private GuiWidget topMostParent;
private PlaneShape bedPlane = new PlaneShape(Vector3.UnitZ, 0, null);
public bool DragOperationActive { get; private set; }
public IObject3D DragDropObject { get; private set; }
2017-03-15 16:17:06 -07:00
/// <summary>
/// Provides a View3DWidget specific drag implementation
/// </summary>
/// <param name="screenSpaceMousePosition">The screen space mouse position.</param>
public void ExternalDragOver(Vector2 screenSpaceMousePosition)
2015-04-08 15:20:10 -07:00
{
if (this.HasBeenClosed)
2017-03-15 16:17:06 -07:00
{
return;
2017-03-15 16:17:06 -07:00
}
// If the mouse is within the MeshViewer process the Drag move
2017-03-15 16:17:06 -07:00
var meshViewerPosition = this.meshViewerWidget.TransformToScreenSpace(meshViewerWidget.LocalBounds);
if (meshViewerPosition.Contains(screenSpaceMousePosition))
2015-05-30 12:48:16 -07:00
{
// If already started, process drag move
if (this.DragOperationActive)
2015-05-30 12:48:16 -07:00
{
this.DragOver(screenSpaceMousePosition);
2017-03-15 16:17:06 -07:00
}
else
2017-03-15 16:17:06 -07:00
{
// Otherwise begin an externally started DragDropOperation hard-coded to use LibraryView->SelectedItems
this.StartDragDrop(
// Project from ListViewItem to ILibraryItem
ApplicationController.Instance.Library.ActiveViewWidget.SelectedItems.Select(l => l.Model),
screenSpaceMousePosition);
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 DragOver(Vector2 screenSpaceMousePosition)
{
// Move the object being dragged
if (this.DragOperationActive
&& this.DragDropObject != null)
{
// Move the DropDropObject the target item
DragSelectedObject(localMousePostion: this.TransformFromParentSpace(topMostParent, screenSpaceMousePosition));
}
2015-04-08 15:20:10 -07:00
}
private void StartDragDrop(IEnumerable<ILibraryItem> items, Vector2 screenSpaceMousePosition)
{
this.DragOperationActive = true;
// Set the hitplane to the bed plane
CurrentSelectInfo.HitPlane = bedPlane;
DragDropObject = new InsertionGroup(
2017-09-28 15:51:31 -07:00
items,
this,
this.Scene,
() => this.DragOperationActive);
// Find intersection position of the mouse with the bed plane
var intersectInfo = GetIntersectPosition(screenSpaceMousePosition);
if (intersectInfo != null)
{
// Set the initial transform on the inject part to the current transform mouse position
var sourceItemBounds = DragDropObject.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
var center = sourceItemBounds.Center;
this.DragDropObject.Matrix *= Matrix4X4.CreateTranslation(-center.x, -center.y, -sourceItemBounds.minXYZ.z);
this.DragDropObject.Matrix *= Matrix4X4.CreateTranslation(new Vector3(intersectInfo.HitPosition));
2017-09-16 01:11:44 -07:00
CurrentSelectInfo.PlaneDownHitPos = intersectInfo.HitPosition;
CurrentSelectInfo.LastMoveDelta = Vector3.Zero;
}
2017-09-16 01:11:44 -07:00
this.deferEditorTillMouseUp = true;
2015-04-08 15:20:10 -07:00
// Add item to scene and select it
2017-09-26 12:52:54 -07:00
this.Scene.Children.Modify(list =>
2017-03-15 16:17:06 -07:00
{
2017-09-26 12:52:54 -07:00
list.Add(this.DragDropObject);
});
Scene.SelectedItem = this.DragDropObject;
2017-03-15 16:17:06 -07:00
}
internal void FinishDrop(bool mouseUpInBounds)
{
if (this.DragOperationActive)
2017-03-15 16:17:06 -07:00
{
this.DragOperationActive = false;
if (mouseUpInBounds)
{
// Create and push the undo operation
this.AddUndoOperation(
2017-10-13 15:00:08 -07:00
new InsertCommand(this, this.Scene, this.DragDropObject));
2017-04-05 19:03:04 -07:00
}
else
2017-04-05 19:03:04 -07:00
{
2017-09-26 12:54:40 -07:00
this.Scene.Children.Modify(list => list.Remove(this.DragDropObject));
this.Scene.ClearSelection();
}
this.DragDropObject = null;
this.deferEditorTillMouseUp = false;
Scene_SelectionChanged(null, null);
this.PartHasBeenChanged();
// Set focus to View3DWidget after drag-drop
UiThread.RunOnIdle(this.Focus);
2017-03-15 16:17:06 -07:00
}
}
public override void OnLoad(EventArgs args)
{
topMostParent = this.TopmostParent();
// Set reference on show
var dragDropData = ApplicationController.Instance.DragDropData;
dragDropData.View3DWidget = this;
2017-10-05 22:32:23 -07:00
dragDropData.SceneContext = sceneContext;
base.OnLoad(args);
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();
}
// 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;
}
}
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)
{
// File system Drop validation
mouseEvent.AcceptDrop = this.AllowDragDrop()
&& mouseEvent.DragFiles?.Count > 0
&& mouseEvent.DragFiles.TrueForAll(filePath => ApplicationController.Instance.IsLoadableFile(filePath));
// View3DWidgets Filesystem DropDrop handler
if (mouseEvent.AcceptDrop
&& this.PositionWithinLocalBounds(mouseEvent.X, mouseEvent.Y))
{
if (this.DragOperationActive)
{
DragOver(screenSpaceMousePosition: this.TransformToScreenSpace(mouseEvent.Position));
}
else
{
// Project DragFiles to IEnumerable<FileSystemFileItem>
this.StartDragDrop(
mouseEvent.DragFiles.Select(path => new FileSystemFileItem(path)),
screenSpaceMousePosition: this.TransformToScreenSpace(mouseEvent.Position));
}
}
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;
world.Translate(-new Vector3(sceneContext.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 (this.DragOperationActive)
{
this.FinishDrop(mouseUpInBounds: true);
}
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;
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());
}
2017-09-19 14:01:32 -07:00
var dualExtrusionAlignButton = ApplicationController.Instance.Theme.MenuButtonFactory.Generate("Align for Dual Extrusion".Localize());
dualExtrusionAlignButton.Margin = new BorderDouble(21, 0);
dualExtrusionAlignButton.HAnchor = HAnchor.Left;
buttonPanel.AddChild(dualExtrusionAlignButton);
AddAlignDelegates(0, AxisAlignment.SourceCoordinateSystem, dualExtrusionAlignButton);
return widget;
}
2017-09-19 14:01:32 -07:00
internal enum AxisAlignment { Min, Center, Max, SourceCoordinateSystem };
2017-08-17 15:21:29 -07:00
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);
2017-09-19 14:01:32 -07:00
AddAlignDelegates(axisIndex, alignment, alignButton);
return alignButton;
}
private void AddAlignDelegates(int axisIndex, AxisAlignment alignment, Button alignButton)
{
alignButton.Click += (sender, e) =>
{
if (Scene.HasSelection)
{
2017-08-22 15:55:52 -07:00
var transformDatas = GetTransforms(axisIndex, alignment);
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-09-19 14:01:32 -07:00
if (Scene.HasSelection)
2017-08-22 15:55:52 -07:00
{
2017-09-19 14:01:32 -07:00
// make a preview of the new positions
var transformDatas = GetTransforms(axisIndex, alignment);
Scene.Children.Modify((list) =>
2017-09-19 14:01:32 -07:00
{
foreach (var transform in transformDatas)
{
var copy = transform.TransformedObject.Clone();
copy.Matrix = transform.RedoTransform;
copy.Color = new RGBA_Bytes(RGBA_Bytes.Gray, 126);
list.Add(copy);
}
});
2017-08-22 15:55:52 -07:00
}
};
alignButton.MouseLeave += (s3, e3) =>
{
2017-09-19 14:01:32 -07:00
if (Scene.HasSelection)
2017-08-22 15:55:52 -07:00
{
2017-09-19 14:01:32 -07:00
// clear the preview of the new positions
Scene.Children.Modify((list) =>
2017-08-22 15:55:52 -07:00
{
for(int i=list.Count-1; i>=0; i--)
2017-09-19 14:01:32 -07:00
{
if (list[i].Color.Alpha0To255 == 126)
{
list.RemoveAt(i);
}
2017-09-19 14:01:32 -07:00
}
});
2017-08-22 15:55:52 -07:00
}
};
}
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);
2017-09-19 14:01:32 -07:00
Vector3 firstSourceOrigin = new Vector3(double.MaxValue, double.MaxValue, double.MaxValue);
2017-08-22 15:55:52 -07:00
// 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:
2017-09-19 14:01:32 -07:00
offset[axisIndex] = totalAABB.maxXYZ[axisIndex] - childAABB.maxXYZ[axisIndex];
break;
case AxisAlignment.SourceCoordinateSystem:
2017-08-22 15:55:52 -07:00
{
2017-09-19 14:01:32 -07:00
// move the object back to the origin
offset = -Vector3.Transform(Vector3.Zero, child.Matrix);
// figure out how to move it back to the start center
if(firstSourceOrigin.x == double.MaxValue)
{
firstSourceOrigin = -offset;
}
offset += firstSourceOrigin;
2017-08-22 15:55:52 -07:00
}
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
}
2017-09-16 01:36:19 -07:00
// TODO: Consider if we should always allow DragDrop or if we should prevent during printer or other scenarios
private bool AllowDragDrop() => true;
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)
2015-05-30 12:48:16 -07:00
{
UiThread.RunOnIdle(() =>
2015-05-30 12:48:16 -07:00
{
2015-07-14 13:38:22 -07:00
processingProgressControl.RatioComplete = progress0To1;
// TODO: filter needed? processingState != processingProgressControl.ProgressMessage
2015-05-30 12:48:16 -07:00
processingProgressControl.ProgressMessage = processingState;
});
timeSinceReported.Restart();
}
}
2017-03-15 16:17:06 -07:00
private void Scene_SelectionChanged(object sender, EventArgs e)
{
if (!Scene.HasSelection)
{
selectedObjectContainer.Visible = false;
2017-03-15 16:17:06 -07:00
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
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;
}
}
selectedObjectPanel.SetActiveItem(selectedItem);
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);
newEditor.HAnchor = HAnchor.Stretch;
newEditor.VAnchor = VAnchor.Fit;
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
VertexStorage zArrow = new VertexStorage();
2017-03-15 16:17:06 -07:00
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
}
public void StartProgress(string rootTask)
{
processingProgressControl.ProcessType = rootTask;
processingProgressControl.Visible = true;
processingProgressControl.PercentComplete = 0;
this.LockEditControls();
}
public void EndProgress()
{
// TODO: Leave on screen for a few seconds to aid in troubleshooting - remove after done investigating
UiThread.RunOnIdle(() => processingProgressControl.Visible = false, 1.2);
this.UnlockEditControls();
this.PartHasBeenChanged();
this.Invalidate();
}
private async void LoadAndAddPartsToPlate(string[] filesToLoad)
2015-05-30 12:48:16 -07:00
{
if (filesToLoad != null && filesToLoad.Length > 0)
2015-05-30 12:48:16 -07:00
{
this.StartProgress("Loading Parts".Localize() + ":");
2015-04-08 15:20:10 -07:00
await Task.Run(() => loadAndAddPartsToPlate(filesToLoad));
2015-04-08 15:20:10 -07:00
if (HasBeenClosed)
{
return;
}
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();
}
}
this.EndProgress();
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 async Task 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 object3D = await 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);
});
if (object3D != null)
{
Scene.Children.Modify(list => list.Add(object3D));
PlatingHelper.MoveToOpenPositionRelativeGroup(object3D, this.Scene.Children);
2014-01-29 19:09:30 -08: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
internal void MakeLowestFaceFlat(IObject3D objectToLayFlatGroup)
2015-04-08 15:20:10 -07:00
{
bool firstVertex = true;
2017-03-15 16:17:06 -07:00
IObject3D objectToLayFlat = objectToLayFlatGroup;
IVertex lowestVertex = null;
Vector3 lowestVertexPosition = Vector3.Zero;
IObject3D itemToLayFlat = null;
2017-03-15 16:17:06 -07:00
// Process each child, checking for the lowest vertex
var objectsToCheck = objectToLayFlat.VisibleMeshes();
foreach (var 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
for (int testIndex = 0; 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];
Vector3 vertexPosition = Vector3.Transform(vertex.Position, itemToCheck.WorldMatrix());
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)
{
Vector3 faceVertexPosition = Vector3.Transform(faceVertex.Position, itemToLayFlat.Matrix);
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
{
Vector3 vertexPosition = Vector3.Transform(vertex.Position, itemToLayFlat.Matrix);
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);
2017-03-15 16:17:06 -07:00
private FlowLayoutWidget editorPanel;
private SelectedObjectPanel selectedObjectPanel;
internal GuiWidget selectedObjectContainer;
2017-10-19 09:04:36 -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
{
this.StartProgress("Saving".Localize() + ":");
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(sceneContext.printItem.FileLocation) != ".mcx")
{
sceneContext.printItem.FileLocation = Path.ChangeExtension(sceneContext.printItem.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(sceneContext.printItem.FileLocation, ApplicationDataStorage.Instance.ApplicationLibraryDataPath);
sceneContext.printItem.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
this.EndProgress();
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 (sceneContext.RendererOptions.SyncToPrint)
2015-05-30 12:48:16 -07:00
{
switch (sceneContext.Printer?.Connection.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
}
2017-10-06 12:30:48 -07:00
UiThread.RunOnIdle(SwitchStateToEditing);
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
private void OpenExportWindow()
{
var exportPage = new ExportPrintItemPage(new[] { new FileSystemFileItem(sceneContext.printItem.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(
2017-09-16 01:11:44 -07:00
sceneContext,
async (returnInfo) =>
{
// 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(sceneContext.printItem.FileLocation)
{
Name = returnInfo.newName
}
});
returnInfo.DestinationContainer.Dispose();
}
}
},
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;
}
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;
this.StartProgress("Preparing Meshes".Localize() + ":");
2017-03-15 16:17:06 -07:00
if (Scene.HasChildren())
2017-03-15 16:17:06 -07:00
{
// TODO: Why is this in widget land? When we load content we should queue trace generation, not when we rebuild ui controls
2017-03-15 16:17:06 -07:00
// CreateSelectionData()
await Task.Run(() =>
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
// Force trace data generation
foreach (var object3D in Scene.Children)
{
object3D.TraceData();
}
});
if (this.HasBeenClosed)
{
return;
}
Scene.SelectFirstChild();
}
this.EndProgress();
2017-03-15 16:17:06 -07:00
viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect;
2017-03-15 16:17:06 -07:00
}
// Before printing persist any changes to disk
internal async Task PersistPlateIfNeeded()
{
// TODO: Clean up caching, restore conditional save once Dirty state is trustworthy
//if (partHasBeenEdited)
{
await this.SaveChanges();
}
}
public void LockEditControls()
{
bottomActionPanel.Enabled = false;
}
2017-03-15 16:17:06 -07:00
public void UnlockEditControls()
2015-05-30 12:48:16 -07:00
{
bottomActionPanel.Enabled = 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.PartSelectVisible = true;
viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect;
2015-05-30 12:48:16 -07:00
wasInSelectMode = false;
}
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;
}
}));
if (sceneContext.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;
normal = Vector3.TransformVector(normal, meshRenderData.WorldMatrix()).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;
2017-09-16 01:11:44 -07:00
private 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
}
}