integrating offline changes
This commit is contained in:
parent
121623bad3
commit
3f8eeda65b
125 changed files with 5442 additions and 5434 deletions
|
|
@ -44,141 +44,140 @@ using MatterHackers.VectorMath;
|
|||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
[ShowUpdateButton]
|
||||
public class CombineObject3D_2 : OperationSourceContainerObject3D, IPropertyGridModifier, IBuildsOnThread
|
||||
{
|
||||
[ShowUpdateButton]
|
||||
public class CombineObject3D_2 : OperationSourceContainerObject3D, IPropertyGridModifier, IBuildsOnThread
|
||||
{
|
||||
private CancellationTokenSource cancellationToken;
|
||||
|
||||
public CombineObject3D_2()
|
||||
{
|
||||
Name = "Combine";
|
||||
}
|
||||
{
|
||||
Name = "Combine";
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
public ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public IplicitSurfaceMethod MeshAnalysis { get; set; }
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public IplicitSurfaceMethod MeshAnalysis { get; set; }
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
#else
|
||||
private ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
private ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
private IplicitSurfaceMethod MeshAnalysis { get; set; }
|
||||
private ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
#endif
|
||||
public bool IsBuilding => this.cancellationToken != null;
|
||||
public bool IsBuilding => this.cancellationToken != null;
|
||||
|
||||
public static void CheckManifoldData(CombineObject3D_2 item, IObject3D result)
|
||||
{
|
||||
bool IsManifold(Mesh mesh)
|
||||
{
|
||||
var meshEdgeList = mesh.NewMeshEdges();
|
||||
public static void CheckManifoldData(CombineObject3D_2 item, IObject3D result)
|
||||
{
|
||||
bool IsManifold(Mesh mesh)
|
||||
{
|
||||
var meshEdgeList = mesh.NewMeshEdges();
|
||||
|
||||
foreach (var meshEdge in meshEdgeList)
|
||||
{
|
||||
if (meshEdge.Faces.Count() != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach (var meshEdge in meshEdgeList)
|
||||
{
|
||||
if (meshEdge.Faces.Count() != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!IsManifold(result.Mesh))
|
||||
{
|
||||
// create a new combine of a and b and add it to the root
|
||||
var combine = new CombineObject3D_2();
|
||||
if (!IsManifold(result.Mesh))
|
||||
{
|
||||
// create a new combine of a and b and add it to the root
|
||||
var combine = new CombineObject3D_2();
|
||||
|
||||
var participants = item.SourceContainer.VisibleMeshes().Where(m => m.WorldOutputType(item.SourceContainer) != PrintOutputTypes.Hole);
|
||||
// all participants are manifold
|
||||
foreach (var participant in participants)
|
||||
{
|
||||
combine.SourceContainer.Children.Add(new Object3D()
|
||||
{
|
||||
Mesh = participant.Mesh.Copy(new CancellationToken()),
|
||||
Matrix = participant.Matrix
|
||||
});
|
||||
}
|
||||
var participants = item.SourceContainer.VisibleMeshes().Where(m => m.WorldOutputType(item.SourceContainer) != PrintOutputTypes.Hole);
|
||||
// all participants are manifold
|
||||
foreach (var participant in participants)
|
||||
{
|
||||
combine.SourceContainer.Children.Add(new Object3D()
|
||||
{
|
||||
Mesh = participant.Mesh.Copy(new CancellationToken()),
|
||||
Matrix = participant.Matrix
|
||||
});
|
||||
}
|
||||
|
||||
var scene = result.Parents().Last();
|
||||
scene.Children.Add(combine);
|
||||
}
|
||||
}
|
||||
var scene = result.Parents().Last();
|
||||
scene.Children.Add(combine);
|
||||
}
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Combine".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
this.cancellationToken = cancellationTokenSource;
|
||||
var progressStatus = new ProgressStatus();
|
||||
reporter.Report(progressStatus);
|
||||
"Combine".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
this.cancellationToken = cancellationTokenSource;
|
||||
reporter?.Invoke(0, null);
|
||||
|
||||
try
|
||||
{
|
||||
Combine(cancellationTokenSource.Token, reporter);
|
||||
try
|
||||
{
|
||||
Combine(cancellationTokenSource.Token, reporter);
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// the combine was canceled set our children to the source object children
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
Children.Modify((list) =>
|
||||
{
|
||||
foreach (var child in SourceContainer.Children)
|
||||
{
|
||||
list.Add(child);
|
||||
}
|
||||
});
|
||||
// the combine was canceled set our children to the source object children
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
Children.Modify((list) =>
|
||||
{
|
||||
foreach (var child in SourceContainer.Children)
|
||||
{
|
||||
list.Add(child);
|
||||
}
|
||||
});
|
||||
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (!NameOverriden)
|
||||
{
|
||||
Name = NameFromChildren();
|
||||
NameOverriden = false;
|
||||
}
|
||||
if (!NameOverriden)
|
||||
{
|
||||
Name = NameFromChildren();
|
||||
NameOverriden = false;
|
||||
}
|
||||
|
||||
this.cancellationToken = null;
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
this.cancellationToken = null;
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
public void Combine()
|
||||
{
|
||||
Combine(CancellationToken.None, null);
|
||||
}
|
||||
public void Combine()
|
||||
{
|
||||
Combine(CancellationToken.None, null);
|
||||
}
|
||||
|
||||
public override string NameFromChildren()
|
||||
{
|
||||
return CalculateName(SourceContainer.Children, " + ");
|
||||
}
|
||||
return CalculateName(SourceContainer.Children, " + ");
|
||||
}
|
||||
|
||||
private void Combine(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
|
||||
private void Combine(CancellationToken cancellationToken, Action<double, string> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
|
|
@ -238,27 +237,27 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
resultsItem.CopyProperties(participants.First(), Object3DPropertyFlags.All & (~Object3DPropertyFlags.Matrix));
|
||||
this.Children.Add(resultsItem);
|
||||
#if DEBUG
|
||||
//resultsItem.Mesh.MergeVertices(.01);
|
||||
//resultsItem.Mesh.CleanAndMerge();
|
||||
//CheckManifoldData(this, resultsItem);
|
||||
//resultsItem.Mesh.MergeVertices(.01);
|
||||
//resultsItem.Mesh.CleanAndMerge();
|
||||
//CheckManifoldData(this, resultsItem);
|
||||
#endif
|
||||
SourceContainer.Visible = false;
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
|
||||
public void CancelBuild()
|
||||
{
|
||||
var threadSafe = this.cancellationToken;
|
||||
if(threadSafe != null)
|
||||
var threadSafe = this.cancellationToken;
|
||||
if (threadSafe != null)
|
||||
{
|
||||
threadSafe.Cancel();
|
||||
threadSafe.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2017, Lars Brubaker, John Lewin
|
||||
Copyright (c) 2023, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -42,25 +42,25 @@ using MatterHackers.VectorMath;
|
|||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
[ShowUpdateButton]
|
||||
public class IntersectionObject3D_2 : OperationSourceContainerObject3D, IPropertyGridModifier
|
||||
{
|
||||
public IntersectionObject3D_2()
|
||||
{
|
||||
Name = "Intersection";
|
||||
}
|
||||
[ShowUpdateButton]
|
||||
public class IntersectionObject3D_2 : OperationSourceContainerObject3D, IPropertyGridModifier
|
||||
{
|
||||
public IntersectionObject3D_2()
|
||||
{
|
||||
Name = "Intersection";
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
public ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public IplicitSurfaceMethod MeshAnalysis { get; set; }
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public IplicitSurfaceMethod MeshAnalysis { get; set; }
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
#else
|
||||
private ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
private ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
|
|
@ -68,90 +68,88 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
private ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
#endif
|
||||
|
||||
private CancellationTokenSource cancellationToken;
|
||||
private CancellationTokenSource cancellationToken;
|
||||
|
||||
public bool IsBuilding => this.cancellationToken != null;
|
||||
public bool IsBuilding => this.cancellationToken != null;
|
||||
|
||||
public void CancelBuild()
|
||||
{
|
||||
var threadSafe = this.cancellationToken;
|
||||
if (threadSafe != null)
|
||||
{
|
||||
threadSafe.Cancel();
|
||||
}
|
||||
}
|
||||
public void CancelBuild()
|
||||
{
|
||||
var threadSafe = this.cancellationToken;
|
||||
if (threadSafe != null)
|
||||
{
|
||||
threadSafe.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Intersection".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
this.cancellationToken = cancellationTokenSource as CancellationTokenSource;
|
||||
var progressStatus = new ProgressStatus();
|
||||
reporter.Report(progressStatus);
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Intersection".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
this.cancellationToken = cancellationTokenSource as CancellationTokenSource;
|
||||
|
||||
try
|
||||
{
|
||||
Intersect(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
Intersect(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (!NameOverriden)
|
||||
{
|
||||
Name = NameFromChildren();
|
||||
NameOverriden = false;
|
||||
}
|
||||
if (!NameOverriden)
|
||||
{
|
||||
Name = NameFromChildren();
|
||||
NameOverriden = false;
|
||||
}
|
||||
|
||||
this.cancellationToken = null;
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
this.cancellationToken = null;
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
public override string NameFromChildren()
|
||||
{
|
||||
return CalculateName(SourceContainer.Children, " & ");
|
||||
}
|
||||
public override string NameFromChildren()
|
||||
{
|
||||
return CalculateName(SourceContainer.Children, " & ");
|
||||
}
|
||||
|
||||
public void Intersect()
|
||||
{
|
||||
Intersect(CancellationToken.None, null);
|
||||
}
|
||||
public void Intersect()
|
||||
{
|
||||
Intersect(CancellationToken.None, null);
|
||||
}
|
||||
|
||||
private void Intersect(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
private void Intersect(CancellationToken cancellationToken, Action<double, string> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
|
||||
var participants = SourceContainer.VisibleMeshes();
|
||||
if (participants.Count() < 2)
|
||||
{
|
||||
if (participants.Count() == 1)
|
||||
{
|
||||
var newMesh = new Object3D();
|
||||
newMesh.CopyProperties(participants.First(), Object3DPropertyFlags.All);
|
||||
newMesh.Mesh = participants.First().Mesh;
|
||||
this.Children.Add(newMesh);
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
var participants = SourceContainer.VisibleMeshes();
|
||||
if (participants.Count() < 2)
|
||||
{
|
||||
if (participants.Count() == 1)
|
||||
{
|
||||
var newMesh = new Object3D();
|
||||
newMesh.CopyProperties(participants.First(), Object3DPropertyFlags.All);
|
||||
newMesh.Mesh = participants.First().Mesh;
|
||||
this.Children.Add(newMesh);
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var items = participants.Select(i => (i.Mesh, i.WorldMatrix(SourceContainer)));
|
||||
var items = participants.Select(i => (i.Mesh, i.WorldMatrix(SourceContainer)));
|
||||
#if false
|
||||
var resultsMesh = BooleanProcessing.DoArray(items,
|
||||
CsgModes.Intersect,
|
||||
|
|
@ -161,69 +159,65 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
reporter,
|
||||
cancellationToken);
|
||||
#else
|
||||
var totalOperations = items.Count() - 1;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
var totalOperations = items.Count() - 1;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
|
||||
var progressStatus = new ProgressStatus();
|
||||
var resultsMesh = items.First().Item1;
|
||||
var keepWorldMatrix = items.First().Item2;
|
||||
|
||||
var resultsMesh = items.First().Item1;
|
||||
var keepWorldMatrix = items.First().Item2;
|
||||
bool first = true;
|
||||
foreach (var next in items)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
foreach (var next in items)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
resultsMesh = BooleanProcessing.Do(resultsMesh,
|
||||
keepWorldMatrix,
|
||||
// other mesh
|
||||
next.Item1,
|
||||
next.Item2,
|
||||
// operation type
|
||||
CsgModes.Intersect,
|
||||
Processing,
|
||||
InputResolution,
|
||||
OutputResolution,
|
||||
// reporting
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
cancellationToken);
|
||||
|
||||
resultsMesh = BooleanProcessing.Do(resultsMesh,
|
||||
keepWorldMatrix,
|
||||
// other mesh
|
||||
next.Item1,
|
||||
next.Item2,
|
||||
// operation type
|
||||
CsgModes.Intersect,
|
||||
Processing,
|
||||
InputResolution,
|
||||
OutputResolution,
|
||||
// reporting
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
progressStatus,
|
||||
cancellationToken);
|
||||
// after the first time we get a result the results mesh is in the right coordinate space
|
||||
keepWorldMatrix = Matrix4X4.Identity;
|
||||
|
||||
// after the first time we get a result the results mesh is in the right coordinate space
|
||||
keepWorldMatrix = Matrix4X4.Identity;
|
||||
|
||||
// report our progress
|
||||
ratioCompleted += amountPerOperation;
|
||||
progressStatus.Progress0To1 = ratioCompleted;
|
||||
reporter?.Report(progressStatus);
|
||||
}
|
||||
// report our progress
|
||||
ratioCompleted += amountPerOperation;
|
||||
reporter?.Invoke(ratioCompleted, null);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (resultsMesh != null)
|
||||
{
|
||||
var resultsItem = new Object3D()
|
||||
{
|
||||
Mesh = resultsMesh
|
||||
};
|
||||
resultsItem.CopyProperties(participants.First(), Object3DPropertyFlags.All & (~Object3DPropertyFlags.Matrix));
|
||||
this.Children.Add(resultsItem);
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
}
|
||||
if (resultsMesh != null)
|
||||
{
|
||||
var resultsItem = new Object3D()
|
||||
{
|
||||
Mesh = resultsMesh
|
||||
};
|
||||
resultsItem.CopyProperties(participants.First(), Object3DPropertyFlags.All & (~Object3DPropertyFlags.Matrix));
|
||||
this.Children.Add(resultsItem);
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
}
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
|||
// first replace spaces with '_'
|
||||
var name = editSelectedName.Text.Replace(' ', '_');
|
||||
// next make sure we don't have the exact name already
|
||||
name = agg_basics.GetNonCollidingName(name, (name) =>
|
||||
name = Util.GetNonCollidingName(name, (name) =>
|
||||
{
|
||||
return !existingNames.Contains(name.ToLower());
|
||||
}, false);
|
||||
|
|
|
|||
|
|
@ -48,179 +48,175 @@ using MatterHackers.VectorMath;
|
|||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
[Obsolete("Use SubtractAndReplaceObject3D_2 instead", false)]
|
||||
[ShowUpdateButton(SuppressPropertyChangeUpdates = true)]
|
||||
public class SubtractAndReplaceObject3D : MeshWrapperObject3D, ISelectableChildContainer
|
||||
{
|
||||
public SubtractAndReplaceObject3D()
|
||||
{
|
||||
Name = "Subtract and Replace";
|
||||
}
|
||||
[Obsolete("Use SubtractAndReplaceObject3D_2 instead", false)]
|
||||
[ShowUpdateButton(SuppressPropertyChangeUpdates = true)]
|
||||
public class SubtractAndReplaceObject3D : MeshWrapperObject3D, ISelectableChildContainer
|
||||
{
|
||||
public SubtractAndReplaceObject3D()
|
||||
{
|
||||
Name = "Subtract and Replace";
|
||||
}
|
||||
|
||||
public SelectedChildren ItemsToSubtract { get; set; } = new SelectedChildren();
|
||||
public SelectedChildren ItemsToSubtract { get; set; } = new SelectedChildren();
|
||||
|
||||
public SelectedChildren SelectedChildren => ItemsToSubtract;
|
||||
public SelectedChildren SelectedChildren => ItemsToSubtract;
|
||||
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
}
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
}
|
||||
|
||||
public void SubtractAndReplace()
|
||||
{
|
||||
SubtractAndReplace(CancellationToken.None, null);
|
||||
}
|
||||
public void SubtractAndReplace()
|
||||
{
|
||||
SubtractAndReplace(CancellationToken.None, null);
|
||||
}
|
||||
|
||||
public void SubtractAndReplace(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
|
||||
{
|
||||
ResetMeshWrapperMeshes(Object3DPropertyFlags.All, cancellationToken);
|
||||
public void SubtractAndReplace(CancellationToken cancellationToken, Action<double, string> reporter)
|
||||
{
|
||||
ResetMeshWrapperMeshes(Object3DPropertyFlags.All, cancellationToken);
|
||||
|
||||
var paintObjects = this.Children
|
||||
.Where((i) => ItemsToSubtract.Contains(i.ID))
|
||||
.SelectMany((h) => h.DescendantsAndSelf())
|
||||
.Where((c) => c.OwnerID == this.ID).ToList();
|
||||
var keepObjects = this.Children
|
||||
.Where((i) => !ItemsToSubtract.Contains(i.ID))
|
||||
.SelectMany((h) => h.DescendantsAndSelf())
|
||||
.Where((c) => c.OwnerID == this.ID).ToList();
|
||||
var paintObjects = this.Children
|
||||
.Where((i) => ItemsToSubtract.Contains(i.ID))
|
||||
.SelectMany((h) => h.DescendantsAndSelf())
|
||||
.Where((c) => c.OwnerID == this.ID).ToList();
|
||||
var keepObjects = this.Children
|
||||
.Where((i) => !ItemsToSubtract.Contains(i.ID))
|
||||
.SelectMany((h) => h.DescendantsAndSelf())
|
||||
.Where((c) => c.OwnerID == this.ID).ToList();
|
||||
|
||||
if (paintObjects.Any()
|
||||
&& keepObjects.Any())
|
||||
{
|
||||
var totalOperations = paintObjects.Count * keepObjects.Count;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
if (paintObjects.Any()
|
||||
&& keepObjects.Any())
|
||||
{
|
||||
var totalOperations = paintObjects.Count * keepObjects.Count;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
|
||||
foreach (var paint in paintObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
|
||||
{
|
||||
var transformedPaint = paint.obj3D.Mesh.Copy(cancellationToken);
|
||||
transformedPaint.Transform(paint.matrix);
|
||||
var inverseRemove = paint.matrix.Inverted;
|
||||
Mesh paintMesh = null;
|
||||
foreach (var paint in paintObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
|
||||
{
|
||||
var transformedPaint = paint.obj3D.Mesh.Copy(cancellationToken);
|
||||
transformedPaint.Transform(paint.matrix);
|
||||
var inverseRemove = paint.matrix.Inverted;
|
||||
Mesh paintMesh = null;
|
||||
|
||||
var progressStatus = new ProgressStatus();
|
||||
foreach (var keep in keepObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
|
||||
{
|
||||
var transformedKeep = keep.obj3D.Mesh.Copy(cancellationToken);
|
||||
transformedKeep.Transform(keep.matrix);
|
||||
foreach (var keep in keepObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
|
||||
{
|
||||
var transformedKeep = keep.obj3D.Mesh.Copy(cancellationToken);
|
||||
transformedKeep.Transform(keep.matrix);
|
||||
|
||||
// remove the paint from the original
|
||||
var subtract = BooleanProcessing.Do(keep.obj3D.Mesh,
|
||||
keep.matrix,
|
||||
paint.obj3D.Mesh,
|
||||
paint.matrix,
|
||||
CsgModes.Subtract,
|
||||
ProcessingModes.Polygons,
|
||||
ProcessingResolution._64,
|
||||
ProcessingResolution._64,
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
progressStatus,
|
||||
cancellationToken);
|
||||
|
||||
var intersect = BooleanProcessing.Do(keep.obj3D.Mesh,
|
||||
keep.matrix,
|
||||
paint.obj3D.Mesh,
|
||||
paint.matrix,
|
||||
CsgModes.Intersect,
|
||||
ProcessingModes.Polygons,
|
||||
ProcessingResolution._64,
|
||||
ProcessingResolution._64,
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
progressStatus,
|
||||
cancellationToken);
|
||||
// remove the paint from the original
|
||||
var subtract = BooleanProcessing.Do(keep.obj3D.Mesh,
|
||||
keep.matrix,
|
||||
paint.obj3D.Mesh,
|
||||
paint.matrix,
|
||||
CsgModes.Subtract,
|
||||
ProcessingModes.Polygons,
|
||||
ProcessingResolution._64,
|
||||
ProcessingResolution._64,
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
cancellationToken);
|
||||
|
||||
var inverseKeep = keep.matrix.Inverted;
|
||||
subtract.Transform(inverseKeep);
|
||||
using (keep.obj3D.RebuildLock())
|
||||
{
|
||||
keep.obj3D.Mesh = subtract;
|
||||
}
|
||||
var intersect = BooleanProcessing.Do(keep.obj3D.Mesh,
|
||||
keep.matrix,
|
||||
paint.obj3D.Mesh,
|
||||
paint.matrix,
|
||||
CsgModes.Intersect,
|
||||
ProcessingModes.Polygons,
|
||||
ProcessingResolution._64,
|
||||
ProcessingResolution._64,
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
cancellationToken);
|
||||
|
||||
// keep all the intersections together
|
||||
if (paintMesh == null)
|
||||
{
|
||||
paintMesh = intersect;
|
||||
}
|
||||
else // union into the current paint
|
||||
{
|
||||
paintMesh = BooleanProcessing.Do(paintMesh,
|
||||
Matrix4X4.Identity,
|
||||
intersect,
|
||||
Matrix4X4.Identity,
|
||||
CsgModes.Subtract,
|
||||
ProcessingModes.Polygons,
|
||||
ProcessingResolution._64,
|
||||
ProcessingResolution._64,
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
progressStatus,
|
||||
cancellationToken);
|
||||
}
|
||||
var inverseKeep = keep.matrix.Inverted;
|
||||
subtract.Transform(inverseKeep);
|
||||
using (keep.obj3D.RebuildLock())
|
||||
{
|
||||
keep.obj3D.Mesh = subtract;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// keep all the intersections together
|
||||
if (paintMesh == null)
|
||||
{
|
||||
paintMesh = intersect;
|
||||
}
|
||||
else // union into the current paint
|
||||
{
|
||||
paintMesh = BooleanProcessing.Do(paintMesh,
|
||||
Matrix4X4.Identity,
|
||||
intersect,
|
||||
Matrix4X4.Identity,
|
||||
CsgModes.Subtract,
|
||||
ProcessingModes.Polygons,
|
||||
ProcessingResolution._64,
|
||||
ProcessingResolution._64,
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
// move the paint mesh back to its original coordinates
|
||||
paintMesh.Transform(inverseRemove);
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
using (paint.obj3D.RebuildLock())
|
||||
{
|
||||
paint.obj3D.Mesh = paintMesh;
|
||||
}
|
||||
// move the paint mesh back to its original coordinates
|
||||
paintMesh.Transform(inverseRemove);
|
||||
|
||||
paint.obj3D.Color = paint.obj3D.WorldColor().WithContrast(keepObjects.First().WorldColor(), 2).ToColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
using (paint.obj3D.RebuildLock())
|
||||
{
|
||||
paint.obj3D.Mesh = paintMesh;
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
{
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
paint.obj3D.Color = paint.obj3D.WorldColor().WithContrast(keepObjects.First().WorldColor(), 2).ToColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spin up a task to calculate the paint
|
||||
return ApplicationController.Instance.Tasks.Execute("Replacing".Localize(), null, (reporter, cancellationTokenSource) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
SubtractAndReplace(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
public override Task Rebuild()
|
||||
{
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
// spin up a task to calculate the paint
|
||||
return ApplicationController.Instance.Tasks.Execute("Replacing".Localize(), null, (reporter, cancellationTokenSource) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
SubtractAndReplace(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
}
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2017, Lars Brubaker, John Lewin
|
||||
Copyright (c) 2023, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -45,36 +45,36 @@ using MatterHackers.VectorMath;
|
|||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
[ShowUpdateButton]
|
||||
public class SubtractAndReplaceObject3D_2 : OperationSourceContainerObject3D, ISelectableChildContainer, ICustomEditorDraw, IPropertyGridModifier
|
||||
{
|
||||
public SubtractAndReplaceObject3D_2()
|
||||
{
|
||||
Name = "Subtract and Replace";
|
||||
}
|
||||
[ShowUpdateButton]
|
||||
public class SubtractAndReplaceObject3D_2 : OperationSourceContainerObject3D, ISelectableChildContainer, ICustomEditorDraw, IPropertyGridModifier
|
||||
{
|
||||
public SubtractAndReplaceObject3D_2()
|
||||
{
|
||||
Name = "Subtract and Replace";
|
||||
}
|
||||
|
||||
public bool DoEditorDraw(bool isSelected)
|
||||
{
|
||||
return isSelected;
|
||||
}
|
||||
public bool DoEditorDraw(bool isSelected)
|
||||
{
|
||||
return isSelected;
|
||||
}
|
||||
|
||||
[HideFromEditor]
|
||||
public SelectedChildren ComputedChildren { get; set; } = new SelectedChildren();
|
||||
[HideFromEditor]
|
||||
public SelectedChildren ComputedChildren { get; set; } = new SelectedChildren();
|
||||
|
||||
[DisplayName("Part(s) to Subtract and Replace")]
|
||||
public SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
|
||||
[DisplayName("Part(s) to Subtract and Replace")]
|
||||
public SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
|
||||
|
||||
#if DEBUG
|
||||
public ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
public ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public IplicitSurfaceMethod MeshAnalysis { get; set; }
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public IplicitSurfaceMethod MeshAnalysis { get; set; }
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
#else
|
||||
private ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
private ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
|
|
@ -82,255 +82,247 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
private ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
#endif
|
||||
|
||||
public void AddEditorTransparents(Object3DControlsLayer layer, List<Object3DView> transparentMeshes, DrawEventArgs e)
|
||||
{
|
||||
if (layer.Scene.SelectedItem != null
|
||||
&& layer.Scene.SelectedItem == this)
|
||||
{
|
||||
var parentOfSubtractTargets = this.SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
public void AddEditorTransparents(Object3DControlsLayer layer, List<Object3DView> transparentMeshes, DrawEventArgs e)
|
||||
{
|
||||
if (layer.Scene.SelectedItem != null
|
||||
&& layer.Scene.SelectedItem == this)
|
||||
{
|
||||
var parentOfSubtractTargets = this.SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
|
||||
var removeObjects = parentOfSubtractTargets.Children
|
||||
.Where(i => SelectedChildren.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes())
|
||||
.ToList();
|
||||
var removeObjects = parentOfSubtractTargets.Children
|
||||
.Where(i => SelectedChildren.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes())
|
||||
.ToList();
|
||||
|
||||
foreach (var item in removeObjects)
|
||||
{
|
||||
var color = item.WorldColor(checkOutputType: true);
|
||||
transparentMeshes.Add(new Object3DView(item, color.WithAlpha(color.Alpha0To1 * .2)));
|
||||
}
|
||||
foreach (var item in removeObjects)
|
||||
{
|
||||
var color = item.WorldColor(checkOutputType: true);
|
||||
transparentMeshes.Add(new Object3DView(item, color.WithAlpha(color.Alpha0To1 * .2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawEditor(Object3DControlsLayer layer, DrawEventArgs e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public void DrawEditor(Object3DControlsLayer layer, DrawEventArgs e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public AxisAlignedBoundingBox GetEditorWorldspaceAABB(Object3DControlsLayer layer)
|
||||
{
|
||||
return AxisAlignedBoundingBox.Empty();
|
||||
}
|
||||
public AxisAlignedBoundingBox GetEditorWorldspaceAABB(Object3DControlsLayer layer)
|
||||
{
|
||||
return AxisAlignedBoundingBox.Empty();
|
||||
}
|
||||
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
}
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
}
|
||||
|
||||
private CancellationTokenSource cancellationToken;
|
||||
private CancellationTokenSource cancellationToken;
|
||||
|
||||
public bool IsBuilding => this.cancellationToken != null;
|
||||
public bool IsBuilding => this.cancellationToken != null;
|
||||
|
||||
public void CancelBuild()
|
||||
{
|
||||
var threadSafe = this.cancellationToken;
|
||||
if (threadSafe != null)
|
||||
{
|
||||
threadSafe.Cancel();
|
||||
}
|
||||
}
|
||||
public void CancelBuild()
|
||||
{
|
||||
var threadSafe = this.cancellationToken;
|
||||
if (threadSafe != null)
|
||||
{
|
||||
threadSafe.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
{
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
public override Task Rebuild()
|
||||
{
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
|
||||
// spin up a task to calculate the paint
|
||||
return ApplicationController.Instance.Tasks.Execute("Replacing".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
this.cancellationToken = cancellationTokenSource as CancellationTokenSource;
|
||||
try
|
||||
{
|
||||
SubtractAndReplace(cancellationTokenSource.Token, reporter);
|
||||
var newComputedChildren = new SelectedChildren();
|
||||
// spin up a task to calculate the paint
|
||||
return ApplicationController.Instance.Tasks.Execute("Replacing".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
this.cancellationToken = cancellationTokenSource as CancellationTokenSource;
|
||||
try
|
||||
{
|
||||
SubtractAndReplace(cancellationTokenSource.Token, reporter);
|
||||
var newComputedChildren = new SelectedChildren();
|
||||
|
||||
foreach (var id in SelectedChildren)
|
||||
{
|
||||
newComputedChildren.Add(id);
|
||||
}
|
||||
foreach (var id in SelectedChildren)
|
||||
{
|
||||
newComputedChildren.Add(id);
|
||||
}
|
||||
|
||||
ComputedChildren = newComputedChildren;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
ComputedChildren = newComputedChildren;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
this.cancellationToken = null;
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
this.cancellationToken = null;
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
public void SubtractAndReplace()
|
||||
{
|
||||
SubtractAndReplace(CancellationToken.None, null);
|
||||
}
|
||||
public void SubtractAndReplace()
|
||||
{
|
||||
SubtractAndReplace(CancellationToken.None, null);
|
||||
}
|
||||
|
||||
private void SubtractAndReplace(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
private void SubtractAndReplace(CancellationToken cancellationToken, Action<double, string> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
|
||||
var parentOfPaintTargets = SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
var parentOfPaintTargets = SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
|
||||
if (parentOfPaintTargets.Children.Count() < 2)
|
||||
{
|
||||
if (parentOfPaintTargets.Children.Count() == 1)
|
||||
{
|
||||
this.Children.Add(SourceContainer.Clone());
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
if (parentOfPaintTargets.Children.Count() < 2)
|
||||
{
|
||||
if (parentOfPaintTargets.Children.Count() == 1)
|
||||
{
|
||||
this.Children.Add(SourceContainer.Clone());
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SubtractObject3D_2.CleanUpSelectedChildrenIDs(this);
|
||||
SubtractObject3D_2.CleanUpSelectedChildrenIDs(this);
|
||||
|
||||
var paintObjects = parentOfPaintTargets.Children
|
||||
.Where((i) => SelectedChildren
|
||||
.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes())
|
||||
.ToList();
|
||||
var paintObjects = parentOfPaintTargets.Children
|
||||
.Where((i) => SelectedChildren
|
||||
.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes())
|
||||
.ToList();
|
||||
|
||||
var keepItems = parentOfPaintTargets.Children
|
||||
.Where((i) => !SelectedChildren
|
||||
.Contains(i.ID));
|
||||
var keepItems = parentOfPaintTargets.Children
|
||||
.Where((i) => !SelectedChildren
|
||||
.Contains(i.ID));
|
||||
|
||||
var keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList();
|
||||
var keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList();
|
||||
|
||||
if (paintObjects.Any()
|
||||
&& keepVisibleItems.Any())
|
||||
{
|
||||
var totalOperations = paintObjects.Count * keepVisibleItems.Count;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
if (paintObjects.Any()
|
||||
&& keepVisibleItems.Any())
|
||||
{
|
||||
var totalOperations = paintObjects.Count * keepVisibleItems.Count;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
|
||||
var progressStatus = new ProgressStatus
|
||||
{
|
||||
Status = "Do CSG"
|
||||
};
|
||||
foreach (var keep in keepVisibleItems)
|
||||
{
|
||||
var keepResultsMesh = keep.Mesh;
|
||||
var keepWorldMatrix = keep.WorldMatrix(SourceContainer);
|
||||
|
||||
foreach (var keep in keepVisibleItems)
|
||||
{
|
||||
var keepResultsMesh = keep.Mesh;
|
||||
var keepWorldMatrix = keep.WorldMatrix(SourceContainer);
|
||||
foreach (var paint in paintObjects)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var paint in paintObjects)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
return;
|
||||
}
|
||||
Mesh paintMesh = BooleanProcessing.Do(keepResultsMesh,
|
||||
keepWorldMatrix,
|
||||
// paint data
|
||||
paint.Mesh,
|
||||
paint.WorldMatrix(SourceContainer),
|
||||
// operation type
|
||||
CsgModes.Intersect,
|
||||
Processing,
|
||||
InputResolution,
|
||||
OutputResolution,
|
||||
// reporting data
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
cancellationToken);
|
||||
|
||||
Mesh paintMesh = BooleanProcessing.Do(keepResultsMesh,
|
||||
keepWorldMatrix,
|
||||
// paint data
|
||||
paint.Mesh,
|
||||
paint.WorldMatrix(SourceContainer),
|
||||
// operation type
|
||||
CsgModes.Intersect,
|
||||
Processing,
|
||||
InputResolution,
|
||||
OutputResolution,
|
||||
// reporting data
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
progressStatus,
|
||||
cancellationToken);
|
||||
keepResultsMesh = BooleanProcessing.Do(keepResultsMesh,
|
||||
keepWorldMatrix,
|
||||
// point data
|
||||
paint.Mesh,
|
||||
paint.WorldMatrix(SourceContainer),
|
||||
// operation type
|
||||
CsgModes.Subtract,
|
||||
Processing,
|
||||
InputResolution,
|
||||
OutputResolution,
|
||||
// reporting data
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
cancellationToken);
|
||||
|
||||
keepResultsMesh = BooleanProcessing.Do(keepResultsMesh,
|
||||
keepWorldMatrix,
|
||||
// point data
|
||||
paint.Mesh,
|
||||
paint.WorldMatrix(SourceContainer),
|
||||
// operation type
|
||||
CsgModes.Subtract,
|
||||
Processing,
|
||||
InputResolution,
|
||||
OutputResolution,
|
||||
// reporting data
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
progressStatus,
|
||||
cancellationToken);
|
||||
// after the first time we get a result the results mesh is in the right coordinate space
|
||||
keepWorldMatrix = Matrix4X4.Identity;
|
||||
|
||||
// after the first time we get a result the results mesh is in the right coordinate space
|
||||
keepWorldMatrix = Matrix4X4.Identity;
|
||||
// store our intersection (paint) results mesh
|
||||
var paintResultsItem = new Object3D()
|
||||
{
|
||||
Mesh = paintMesh,
|
||||
Visible = false,
|
||||
OwnerID = paint.ID
|
||||
};
|
||||
// copy all the properties but the matrix
|
||||
paintResultsItem.CopyWorldProperties(paint, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible)));
|
||||
// and add it to this
|
||||
this.Children.Add(paintResultsItem);
|
||||
|
||||
// store our intersection (paint) results mesh
|
||||
var paintResultsItem = new Object3D()
|
||||
{
|
||||
Mesh = paintMesh,
|
||||
Visible = false,
|
||||
OwnerID = paint.ID
|
||||
};
|
||||
// copy all the properties but the matrix
|
||||
paintResultsItem.CopyWorldProperties(paint, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible)));
|
||||
// and add it to this
|
||||
this.Children.Add(paintResultsItem);
|
||||
// report our progress
|
||||
ratioCompleted += amountPerOperation;
|
||||
reporter?.Invoke(ratioCompleted, "Do CSG".Localize());
|
||||
}
|
||||
|
||||
// report our progress
|
||||
ratioCompleted += amountPerOperation;
|
||||
progressStatus.Progress0To1 = ratioCompleted;
|
||||
reporter?.Report(progressStatus);
|
||||
}
|
||||
// store our results mesh
|
||||
var keepResultsItem = new Object3D()
|
||||
{
|
||||
Mesh = keepResultsMesh,
|
||||
Visible = false,
|
||||
OwnerID = keep.ID
|
||||
};
|
||||
// copy all the properties but the matrix
|
||||
keepResultsItem.CopyWorldProperties(keep, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible)));
|
||||
// and add it to this
|
||||
this.Children.Add(keepResultsItem);
|
||||
}
|
||||
|
||||
// store our results mesh
|
||||
var keepResultsItem = new Object3D()
|
||||
{
|
||||
Mesh = keepResultsMesh,
|
||||
Visible = false,
|
||||
OwnerID = keep.ID
|
||||
};
|
||||
// copy all the properties but the matrix
|
||||
keepResultsItem.CopyWorldProperties(keep, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible)));
|
||||
// and add it to this
|
||||
this.Children.Add(keepResultsItem);
|
||||
}
|
||||
foreach (var child in Children)
|
||||
{
|
||||
child.Visible = true;
|
||||
}
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
child.Visible = true;
|
||||
}
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
}
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2017, Lars Brubaker, John Lewin
|
||||
Copyright (c) 2023, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -46,146 +46,139 @@ using MatterHackers.PolygonMesh.Csg;
|
|||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
[Obsolete("Use SubtractObject3D_2 instead", false)]
|
||||
[ShowUpdateButton(SuppressPropertyChangeUpdates = true)]
|
||||
public class SubtractObject3D : MeshWrapperObject3D, ISelectableChildContainer
|
||||
{
|
||||
public SubtractObject3D()
|
||||
{
|
||||
Name = "Subtract";
|
||||
}
|
||||
[Obsolete("Use SubtractObject3D_2 instead", false)]
|
||||
[ShowUpdateButton(SuppressPropertyChangeUpdates = true)]
|
||||
public class SubtractObject3D : MeshWrapperObject3D, ISelectableChildContainer
|
||||
{
|
||||
public SubtractObject3D()
|
||||
{
|
||||
Name = "Subtract";
|
||||
}
|
||||
|
||||
public SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
|
||||
public SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
|
||||
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
|
||||
// spin up a task to remove holes from the objects in the group
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Subtract".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
var progressStatus = new ProgressStatus();
|
||||
reporter.Report(progressStatus);
|
||||
// spin up a task to remove holes from the objects in the group
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Subtract".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Subtract(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Subtract(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
public void Subtract()
|
||||
{
|
||||
Subtract(CancellationToken.None, null);
|
||||
}
|
||||
|
||||
public void Subtract()
|
||||
{
|
||||
Subtract(CancellationToken.None, null);
|
||||
}
|
||||
public void Subtract(CancellationToken cancellationToken, Action<double, string> reporter)
|
||||
{
|
||||
ResetMeshWrapperMeshes(Object3DPropertyFlags.All, cancellationToken);
|
||||
|
||||
public void Subtract(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
|
||||
{
|
||||
ResetMeshWrapperMeshes(Object3DPropertyFlags.All, cancellationToken);
|
||||
bool ItemInSubtractList(IObject3D item)
|
||||
{
|
||||
if (SelectedChildren.Contains(item.ID))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ItemInSubtractList(IObject3D item)
|
||||
{
|
||||
if (SelectedChildren.Contains(item.ID))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// check if the wrapped item is in the subtract list
|
||||
if (item.Children.Count > 0 && SelectedChildren.Contains(item.Children.First().ID))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if the wrapped item is in the subtract list
|
||||
if (item.Children.Count > 0 && SelectedChildren.Contains(item.Children.First().ID))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
var removeObjects = this.Children
|
||||
.Where(i => ItemInSubtractList(i))
|
||||
.SelectMany(h => h.DescendantsAndSelf())
|
||||
.Where(c => c.OwnerID == this.ID).ToList();
|
||||
var keepObjects = this.Children
|
||||
.Where(i => !ItemInSubtractList(i))
|
||||
.SelectMany(h => h.DescendantsAndSelf())
|
||||
.Where(c => c.OwnerID == this.ID).ToList();
|
||||
|
||||
var removeObjects = this.Children
|
||||
.Where(i => ItemInSubtractList(i))
|
||||
.SelectMany(h => h.DescendantsAndSelf())
|
||||
.Where(c => c.OwnerID == this.ID).ToList();
|
||||
var keepObjects = this.Children
|
||||
.Where(i => !ItemInSubtractList(i))
|
||||
.SelectMany(h => h.DescendantsAndSelf())
|
||||
.Where(c => c.OwnerID == this.ID).ToList();
|
||||
if (removeObjects.Any()
|
||||
&& keepObjects.Any())
|
||||
{
|
||||
var totalOperations = removeObjects.Count * keepObjects.Count;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
|
||||
if (removeObjects.Any()
|
||||
&& keepObjects.Any())
|
||||
{
|
||||
var totalOperations = removeObjects.Count * keepObjects.Count;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
foreach (var remove in removeObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
|
||||
{
|
||||
foreach (var keep in keepObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
|
||||
{
|
||||
reporter?.Invoke(0, "Do CSG".Localize());
|
||||
var result = BooleanProcessing.Do(keep.obj3D.Mesh,
|
||||
keep.matrix,
|
||||
remove.obj3D.Mesh,
|
||||
remove.matrix,
|
||||
CsgModes.Subtract,
|
||||
ProcessingModes.Polygons,
|
||||
ProcessingResolution._64,
|
||||
ProcessingResolution._64,
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
cancellationToken);
|
||||
var inverse = keep.matrix.Inverted;
|
||||
result.Transform(inverse);
|
||||
|
||||
ProgressStatus progressStatus = new ProgressStatus();
|
||||
foreach (var remove in removeObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
|
||||
{
|
||||
foreach (var keep in keepObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
|
||||
{
|
||||
progressStatus.Status = "Do CSG";
|
||||
reporter?.Report(progressStatus);
|
||||
var result = BooleanProcessing.Do(keep.obj3D.Mesh,
|
||||
keep.matrix,
|
||||
remove.obj3D.Mesh,
|
||||
remove.matrix,
|
||||
CsgModes.Subtract,
|
||||
ProcessingModes.Polygons,
|
||||
ProcessingResolution._64,
|
||||
ProcessingResolution._64,
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
progressStatus,
|
||||
cancellationToken);
|
||||
var inverse = keep.matrix.Inverted;
|
||||
result.Transform(inverse);
|
||||
using (keep.obj3D.RebuildLock())
|
||||
{
|
||||
keep.obj3D.Mesh = result;
|
||||
}
|
||||
|
||||
using (keep.obj3D.RebuildLock())
|
||||
{
|
||||
keep.obj3D.Mesh = result;
|
||||
}
|
||||
ratioCompleted += amountPerOperation;
|
||||
reporter?.Invoke(ratioCompleted, null);
|
||||
}
|
||||
|
||||
ratioCompleted += amountPerOperation;
|
||||
progressStatus.Progress0To1 = ratioCompleted;
|
||||
reporter?.Report(progressStatus);
|
||||
}
|
||||
|
||||
remove.obj3D.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
remove.obj3D.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,29 +44,29 @@ using MatterHackers.VectorMath;
|
|||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
[ShowUpdateButton]
|
||||
public class SubtractObject3D_2 : OperationSourceContainerObject3D, ISelectableChildContainer, ICustomEditorDraw, IPropertyGridModifier, IBuildsOnThread
|
||||
{
|
||||
public SubtractObject3D_2()
|
||||
{
|
||||
Name = "Subtract";
|
||||
NameOverriden = false;
|
||||
}
|
||||
[ShowUpdateButton]
|
||||
public class SubtractObject3D_2 : OperationSourceContainerObject3D, ISelectableChildContainer, ICustomEditorDraw, IPropertyGridModifier, IBuildsOnThread
|
||||
{
|
||||
public SubtractObject3D_2()
|
||||
{
|
||||
Name = "Subtract";
|
||||
NameOverriden = false;
|
||||
}
|
||||
|
||||
[DisplayName("Part(s) to Subtract")]
|
||||
public virtual SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
|
||||
[DisplayName("Part(s) to Subtract")]
|
||||
public virtual SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
|
||||
|
||||
#if DEBUG
|
||||
public ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
public ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public IplicitSurfaceMethod MeshAnalysis { get; set; }
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public IplicitSurfaceMethod MeshAnalysis { get; set; }
|
||||
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||
public ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
#else
|
||||
private ProcessingModes Processing { get; set; } = ProcessingModes.Polygons;
|
||||
private ProcessingResolution OutputResolution { get; set; } = ProcessingResolution._64;
|
||||
|
|
@ -74,266 +74,264 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
private ProcessingResolution InputResolution { get; set; } = ProcessingResolution._64;
|
||||
#endif
|
||||
|
||||
public bool RemoveSubtractObjects { get; set; } = true;
|
||||
public bool RemoveSubtractObjects { get; set; } = true;
|
||||
|
||||
public bool DoEditorDraw(bool isSelected)
|
||||
public bool DoEditorDraw(bool isSelected)
|
||||
{
|
||||
return isSelected;
|
||||
return isSelected;
|
||||
}
|
||||
|
||||
public void AddEditorTransparents(Object3DControlsLayer layer, List<Object3DView> transparentMeshes, DrawEventArgs e)
|
||||
{
|
||||
if (layer.Scene.SelectedItem != null
|
||||
&& layer.Scene.SelectedItem == this)
|
||||
{
|
||||
var parentOfSubtractTargets = this.SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
public void AddEditorTransparents(Object3DControlsLayer layer, List<Object3DView> transparentMeshes, DrawEventArgs e)
|
||||
{
|
||||
if (layer.Scene.SelectedItem != null
|
||||
&& layer.Scene.SelectedItem == this)
|
||||
{
|
||||
var parentOfSubtractTargets = this.SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
|
||||
var removeObjects = parentOfSubtractTargets.Children
|
||||
.Where(i => SelectedChildren.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes())
|
||||
.ToList();
|
||||
var removeObjects = parentOfSubtractTargets.Children
|
||||
.Where(i => SelectedChildren.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes())
|
||||
.ToList();
|
||||
|
||||
foreach (var item in removeObjects)
|
||||
{
|
||||
var color = item.WorldColor(checkOutputType: true);
|
||||
transparentMeshes.Add(new Object3DView(item, color.WithAlpha(color.Alpha0To1 * .2)));
|
||||
}
|
||||
foreach (var item in removeObjects)
|
||||
{
|
||||
var color = item.WorldColor(checkOutputType: true);
|
||||
transparentMeshes.Add(new Object3DView(item, color.WithAlpha(color.Alpha0To1 * .2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override async void WrapSelectedItemAndSelect(InteractiveScene scene)
|
||||
{
|
||||
// this will ask the subtract to do a rebuild
|
||||
// this will ask the subtract to do a rebuild
|
||||
base.WrapSelectedItemAndSelect(scene);
|
||||
|
||||
if (SelectedChildren.Count == 0)
|
||||
{
|
||||
SelectedChildren.Add(SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf().Children.Last().ID);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawEditor(Object3DControlsLayer layer, DrawEventArgs e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public AxisAlignedBoundingBox GetEditorWorldspaceAABB(Object3DControlsLayer layer)
|
||||
{
|
||||
return AxisAlignedBoundingBox.Empty();
|
||||
}
|
||||
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateArgs)
|
||||
{
|
||||
if ((invalidateArgs.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateArgs.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if ((invalidateArgs.InvalidateType.HasFlag(InvalidateType.Properties) && invalidateArgs.Source == this))
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (SheetObject3D.NeedsRebuild(this, invalidateArgs))
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if(invalidateArgs.InvalidateType.HasFlag(InvalidateType.Name)
|
||||
&& !NameOverriden)
|
||||
{
|
||||
Name = NameFromChildren();
|
||||
NameOverriden = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnInvalidate(invalidateArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private CancellationTokenSource cancellationToken;
|
||||
|
||||
public bool IsBuilding => this.cancellationToken != null;
|
||||
|
||||
public void CancelBuild()
|
||||
{
|
||||
var threadSafe = this.cancellationToken;
|
||||
if (threadSafe != null)
|
||||
{
|
||||
threadSafe.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Subtract".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
this.cancellationToken = cancellationTokenSource;
|
||||
var progressStatus = new ProgressStatus();
|
||||
reporter.Report(progressStatus);
|
||||
|
||||
try
|
||||
{
|
||||
Subtract(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (!NameOverriden)
|
||||
{
|
||||
Name = NameFromChildren();
|
||||
NameOverriden = false;
|
||||
}
|
||||
|
||||
this.cancellationToken = null;
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
public void Subtract()
|
||||
{
|
||||
Subtract(CancellationToken.None, null);
|
||||
}
|
||||
|
||||
private static (IEnumerable<IObject3D>, IEnumerable<IObject3D>) GetSubtractItems(IObject3D source, SelectedChildren selectedChildren)
|
||||
{
|
||||
var parentOfSubtractTargets = source.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
|
||||
// if there are 0 results
|
||||
if (parentOfSubtractTargets.Children.Count() == 0)
|
||||
if (SelectedChildren.Count == 0)
|
||||
{
|
||||
return (null, null);
|
||||
SelectedChildren.Add(SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf().Children.Last().ID);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawEditor(Object3DControlsLayer layer, DrawEventArgs e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public AxisAlignedBoundingBox GetEditorWorldspaceAABB(Object3DControlsLayer layer)
|
||||
{
|
||||
return AxisAlignedBoundingBox.Empty();
|
||||
}
|
||||
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateArgs)
|
||||
{
|
||||
if ((invalidateArgs.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateArgs.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if ((invalidateArgs.InvalidateType.HasFlag(InvalidateType.Properties) && invalidateArgs.Source == this))
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (Expressions.NeedRebuild(this, invalidateArgs))
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (invalidateArgs.InvalidateType.HasFlag(InvalidateType.Name)
|
||||
&& !NameOverriden)
|
||||
{
|
||||
Name = NameFromChildren();
|
||||
NameOverriden = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnInvalidate(invalidateArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private CancellationTokenSource cancellationToken;
|
||||
|
||||
public bool IsBuilding => this.cancellationToken != null;
|
||||
|
||||
public void CancelBuild()
|
||||
{
|
||||
var threadSafe = this.cancellationToken;
|
||||
if (threadSafe != null)
|
||||
{
|
||||
threadSafe.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Subtract".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
this.cancellationToken = cancellationTokenSource;
|
||||
|
||||
try
|
||||
{
|
||||
Subtract(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (!NameOverriden)
|
||||
{
|
||||
Name = NameFromChildren();
|
||||
NameOverriden = false;
|
||||
}
|
||||
|
||||
this.cancellationToken = null;
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
public void Subtract()
|
||||
{
|
||||
Subtract(CancellationToken.None, null);
|
||||
}
|
||||
|
||||
private static (IEnumerable<IObject3D>, IEnumerable<IObject3D>) GetSubtractItems(IObject3D source, SelectedChildren selectedChildren)
|
||||
{
|
||||
var parentOfSubtractTargets = source.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
|
||||
// if there are 0 results
|
||||
if (parentOfSubtractTargets.Children.Count() == 0)
|
||||
{
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
// if there is only 1 result (regardless of it being a keep or remove) return it as a keep
|
||||
if (parentOfSubtractTargets.Children.Count() == 1)
|
||||
{
|
||||
return (new IObject3D[] { source }, null);
|
||||
}
|
||||
|
||||
var removeItems = parentOfSubtractTargets.Children
|
||||
.Where((i) => selectedChildren
|
||||
.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes());
|
||||
|
||||
var keepItems = parentOfSubtractTargets.Children
|
||||
.Where((i) => !selectedChildren
|
||||
.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes());
|
||||
|
||||
return (keepItems, removeItems);
|
||||
}
|
||||
|
||||
private void Subtract(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
|
||||
CleanUpSelectedChildrenIDs(this);
|
||||
|
||||
var (keepItems, removeItems) = GetSubtractItems(SourceContainer, SelectedChildren);
|
||||
|
||||
var resultItems = DoSubtract(SourceContainer,
|
||||
keepItems,
|
||||
removeItems,
|
||||
reporter,
|
||||
cancellationToken,
|
||||
Processing,
|
||||
InputResolution,
|
||||
OutputResolution);
|
||||
|
||||
foreach(var resultsItem in resultItems)
|
||||
// if there is only 1 result (regardless of it being a keep or remove) return it as a keep
|
||||
if (parentOfSubtractTargets.Children.Count() == 1)
|
||||
{
|
||||
this.Children.Add(resultsItem);
|
||||
return (new IObject3D[] { source }, null);
|
||||
}
|
||||
|
||||
if (!RemoveSubtractObjects)
|
||||
{
|
||||
this.Children.Modify((list) =>
|
||||
{
|
||||
foreach (var item in removeItems)
|
||||
{
|
||||
var newObject = new Object3D()
|
||||
{
|
||||
Mesh = item.Mesh
|
||||
};
|
||||
var removeItems = parentOfSubtractTargets.Children
|
||||
.Where((i) => selectedChildren
|
||||
.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes());
|
||||
|
||||
newObject.CopyWorldProperties(item, SourceContainer, Object3DPropertyFlags.All & (~Object3DPropertyFlags.Visible));
|
||||
list.Add(newObject);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
var keepItems = parentOfSubtractTargets.Children
|
||||
.Where((i) => !selectedChildren
|
||||
.Contains(i.ID))
|
||||
.SelectMany(c => c.VisibleMeshes());
|
||||
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
// we only have the source item, leave it visible
|
||||
}
|
||||
else // hide the source and show the children
|
||||
{
|
||||
bool first = true;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
// hide the source item
|
||||
child.Visible = false;
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
child.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (keepItems, removeItems);
|
||||
}
|
||||
|
||||
public static void CleanUpSelectedChildrenIDs(OperationSourceContainerObject3D item)
|
||||
{
|
||||
if (item is ISelectableChildContainer selectableChildContainer)
|
||||
{
|
||||
var parentOfSubtractTargets = item.SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
private void Subtract(CancellationToken cancellationToken, Action<double, string> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
|
||||
var allVisibleIDs = parentOfSubtractTargets.Children.Select(i => i.ID);
|
||||
// remove any names from SelectedChildren that are not a child we can select
|
||||
foreach (var id in selectableChildContainer.SelectedChildren.ToArray())
|
||||
{
|
||||
if (!allVisibleIDs.Contains(id))
|
||||
{
|
||||
selectableChildContainer.SelectedChildren.Remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CleanUpSelectedChildrenIDs(this);
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
var (keepItems, removeItems) = GetSubtractItems(SourceContainer, SelectedChildren);
|
||||
|
||||
var resultItems = DoSubtract(SourceContainer,
|
||||
keepItems,
|
||||
removeItems,
|
||||
reporter,
|
||||
cancellationToken,
|
||||
Processing,
|
||||
InputResolution,
|
||||
OutputResolution);
|
||||
|
||||
foreach (var resultsItem in resultItems)
|
||||
{
|
||||
this.Children.Add(resultsItem);
|
||||
|
||||
if (!RemoveSubtractObjects)
|
||||
{
|
||||
this.Children.Modify((list) =>
|
||||
{
|
||||
foreach (var item in removeItems)
|
||||
{
|
||||
var newObject = new Object3D()
|
||||
{
|
||||
Mesh = item.Mesh
|
||||
};
|
||||
|
||||
newObject.CopyWorldProperties(item, SourceContainer, Object3DPropertyFlags.All & (~Object3DPropertyFlags.Visible));
|
||||
list.Add(newObject);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
// we only have the source item, leave it visible
|
||||
}
|
||||
else // hide the source and show the children
|
||||
{
|
||||
bool first = true;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
// hide the source item
|
||||
child.Visible = false;
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
child.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void CleanUpSelectedChildrenIDs(OperationSourceContainerObject3D item)
|
||||
{
|
||||
if (item is ISelectableChildContainer selectableChildContainer)
|
||||
{
|
||||
var parentOfSubtractTargets = item.SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
|
||||
var allVisibleIDs = parentOfSubtractTargets.Children.Select(i => i.ID);
|
||||
// remove any names from SelectedChildren that are not a child we can select
|
||||
foreach (var id in selectableChildContainer.SelectedChildren.ToArray())
|
||||
{
|
||||
if (!allVisibleIDs.Contains(id))
|
||||
{
|
||||
selectableChildContainer.SelectedChildren.Remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
|
||||
public override string NameFromChildren()
|
||||
{
|
||||
var (keepItems, removeItems) = GetSubtractItems(SourceContainer, SelectedChildren);
|
||||
return CalculateName(keepItems, ", ", " - ", removeItems, ", ");
|
||||
}
|
||||
}
|
||||
var (keepItems, removeItems) = GetSubtractItems(SourceContainer, SelectedChildren);
|
||||
return CalculateName(keepItems, ", ", " - ", removeItems, ", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2017, Lars Brubaker, John Lewin
|
||||
Copyright (c) 2023, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -27,12 +27,6 @@ of the authors and should not be interpreted as representing official policies,
|
|||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
|
|
@ -41,221 +35,221 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
|
||||
using MatterHackers.VectorMath;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
public class SubtractPathObject3D : OperationSourceContainerObject3D, IEditorDraw, IObject3DControlsProvider
|
||||
{
|
||||
public SubtractPathObject3D()
|
||||
{
|
||||
Name = "Subtract";
|
||||
}
|
||||
public class SubtractPathObject3D : OperationSourceContainerObject3D, IEditorDraw, IObject3DControlsProvider, IPrimaryOperationsSpecifier
|
||||
{
|
||||
public SubtractPathObject3D()
|
||||
{
|
||||
Name = "Subtract";
|
||||
}
|
||||
|
||||
[DisplayName("Part(s) to Subtract")]
|
||||
public SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
|
||||
[DisplayName("Part(s) to Subtract")]
|
||||
public SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
|
||||
|
||||
public void DrawEditor(Object3DControlsLayer layer, DrawEventArgs e)
|
||||
{
|
||||
this.DrawPath();
|
||||
}
|
||||
public void DrawEditor(Object3DControlsLayer layer, DrawEventArgs e)
|
||||
{
|
||||
this.DrawPath();
|
||||
}
|
||||
|
||||
public AxisAlignedBoundingBox GetEditorWorldspaceAABB(Object3DControlsLayer layer)
|
||||
{
|
||||
return this.GetWorldspaceAabbOfDrawPath();
|
||||
}
|
||||
public AxisAlignedBoundingBox GetEditorWorldspaceAABB(Object3DControlsLayer layer)
|
||||
{
|
||||
return this.GetWorldspaceAabbOfDrawPath();
|
||||
}
|
||||
|
||||
public void AddObject3DControls(Object3DControlsLayer object3DControlsLayer)
|
||||
{
|
||||
object3DControlsLayer.AddControls(ControlTypes.Standard2D);
|
||||
}
|
||||
public void AddObject3DControls(Object3DControlsLayer object3DControlsLayer)
|
||||
{
|
||||
object3DControlsLayer.AddControls(ControlTypes.Standard2D);
|
||||
}
|
||||
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
}
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|
||||
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
await Rebuild();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanApply => true;
|
||||
public override bool CanApply => true;
|
||||
|
||||
public override void Apply(UndoBuffer undoBuffer)
|
||||
{
|
||||
this.FlattenToPathObject(undoBuffer);
|
||||
}
|
||||
public override void Apply(UndoBuffer undoBuffer)
|
||||
{
|
||||
this.FlattenToPathObject(undoBuffer);
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Subtract".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
var progressStatus = new ProgressStatus();
|
||||
reporter.Report(progressStatus);
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Subtract".Localize(),
|
||||
null,
|
||||
(reporter, cancellationTokenSource) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Subtract(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Subtract(cancellationTokenSource.Token, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
// set the mesh to show the path
|
||||
if (this.GetVertexSource() != null)
|
||||
{
|
||||
var extrudeMesh = this.GetVertexSource().Extrude(Constants.PathPolygonsHeight);
|
||||
if (extrudeMesh.Vertices.Count() > 5)
|
||||
{
|
||||
this.Mesh = extrudeMesh;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Mesh = null;
|
||||
}
|
||||
}
|
||||
|
||||
// set the mesh to show the path
|
||||
if (this.GetVertexSource() != null)
|
||||
{
|
||||
var extrudeMesh = this.GetVertexSource().Extrude(Constants.PathPolygonsHeight);
|
||||
if (extrudeMesh.Vertices.Count() > 5)
|
||||
{
|
||||
this.Mesh = extrudeMesh;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Mesh = null;
|
||||
}
|
||||
}
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
rebuildLocks.Dispose();
|
||||
this.CancelAllParentBuilding();
|
||||
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
public void Subtract()
|
||||
{
|
||||
Subtract(CancellationToken.None, null);
|
||||
}
|
||||
|
||||
public void Subtract()
|
||||
{
|
||||
Subtract(CancellationToken.None, null);
|
||||
}
|
||||
private void Subtract(CancellationToken cancellationToken, Action<double, string> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
|
||||
private void Subtract(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
var parentOfSubtractTargets = SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
|
||||
var parentOfSubtractTargets = SourceContainer.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
if (parentOfSubtractTargets.Children.Count() < 2)
|
||||
{
|
||||
if (parentOfSubtractTargets.Children.Count() == 1)
|
||||
{
|
||||
this.Children.Add(SourceContainer.Clone());
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
|
||||
if (parentOfSubtractTargets.Children.Count() < 2)
|
||||
{
|
||||
if (parentOfSubtractTargets.Children.Count() == 1)
|
||||
{
|
||||
this.Children.Add(SourceContainer.Clone());
|
||||
SourceContainer.Visible = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
CleanUpSelectedChildrenNames(this);
|
||||
|
||||
CleanUpSelectedChildrenNames(this);
|
||||
var removeVisibleItems = parentOfSubtractTargets.Children
|
||||
.Where((i) => SelectedChildren
|
||||
.Contains(i.ID))
|
||||
.SelectMany(c => c.VisiblePaths())
|
||||
.ToList();
|
||||
|
||||
var removeVisibleItems = parentOfSubtractTargets.Children
|
||||
.Where((i) => SelectedChildren
|
||||
.Contains(i.ID))
|
||||
.SelectMany(c => c.VisiblePaths())
|
||||
.ToList();
|
||||
var keepItems = parentOfSubtractTargets.Children
|
||||
.Where((i) => !SelectedChildren
|
||||
.Contains(i.ID));
|
||||
|
||||
var keepItems = parentOfSubtractTargets.Children
|
||||
.Where((i) => !SelectedChildren
|
||||
.Contains(i.ID));
|
||||
var keepVisibleItems = keepItems.SelectMany(c => c.VisiblePaths()).ToList();
|
||||
|
||||
var keepVisibleItems = keepItems.SelectMany(c => c.VisiblePaths()).ToList();
|
||||
if (removeVisibleItems.Any()
|
||||
&& keepVisibleItems.Any())
|
||||
{
|
||||
var totalOperations = removeVisibleItems.Count * keepVisibleItems.Count;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
|
||||
if (removeVisibleItems.Any()
|
||||
&& keepVisibleItems.Any())
|
||||
{
|
||||
var totalOperations = removeVisibleItems.Count * keepVisibleItems.Count;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
bool first = true;
|
||||
foreach (var keep in keepVisibleItems)
|
||||
{
|
||||
var resultsVertexSource = keep.GetVertexSource().Transform(keep.Matrix);
|
||||
|
||||
var progressStatus = new ProgressStatus
|
||||
{
|
||||
Status = "Do Subtract"
|
||||
};
|
||||
foreach (var remove in removeVisibleItems)
|
||||
{
|
||||
resultsVertexSource = resultsVertexSource.MergePaths(remove.GetVertexSource().Transform(remove.Matrix), ClipperLib.ClipType.ctDifference);
|
||||
|
||||
bool first = true;
|
||||
foreach (var keep in keepVisibleItems)
|
||||
{
|
||||
var resultsVertexSource = keep.GetVertexSource().Transform(keep.Matrix);
|
||||
// report our progress
|
||||
ratioCompleted += amountPerOperation;
|
||||
reporter?.Invoke(ratioCompleted, "Do Subtract".Localize());
|
||||
}
|
||||
|
||||
foreach (var remove in removeVisibleItems)
|
||||
{
|
||||
resultsVertexSource = resultsVertexSource.MergePaths(remove.GetVertexSource().Transform(remove.Matrix), ClipperLib.ClipType.ctDifference);
|
||||
if (first)
|
||||
{
|
||||
this.VertexStorage = new VertexStorage(resultsVertexSource);
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.GetVertexSource().MergePaths(resultsVertexSource, ClipperLib.ClipType.ctUnion);
|
||||
}
|
||||
}
|
||||
|
||||
// report our progress
|
||||
ratioCompleted += amountPerOperation;
|
||||
progressStatus.Progress0To1 = ratioCompleted;
|
||||
reporter?.Report(progressStatus);
|
||||
}
|
||||
// this.VertexSource = this.VertexSource.Transform(Matrix.Inverted);
|
||||
first = true;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
// hide the source item
|
||||
child.Visible = false;
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
child.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
this.VertexStorage = new VertexStorage(resultsVertexSource);
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.GetVertexSource().MergePaths(resultsVertexSource, ClipperLib.ClipType.ctUnion);
|
||||
}
|
||||
}
|
||||
public static void CleanUpSelectedChildrenNames(OperationSourceContainerObject3D item)
|
||||
{
|
||||
if (item is ISelectableChildContainer selectableChildContainer)
|
||||
{
|
||||
var parentOfSubtractTargets = item.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
|
||||
// this.VertexSource = this.VertexSource.Transform(Matrix.Inverted);
|
||||
first = true;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
// hide the source item
|
||||
child.Visible = false;
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
child.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var allVisibleNames = parentOfSubtractTargets.Children.Select(i => i.ID);
|
||||
// remove any names from SelectedChildren that are not a child we can select
|
||||
foreach (var name in selectableChildContainer.SelectedChildren.ToArray())
|
||||
{
|
||||
if (!allVisibleNames.Contains(name))
|
||||
{
|
||||
selectableChildContainer.SelectedChildren.Remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void CleanUpSelectedChildrenNames(OperationSourceContainerObject3D item)
|
||||
{
|
||||
if (item is ISelectableChildContainer selectableChildContainer)
|
||||
{
|
||||
var parentOfSubtractTargets = item.FirstWithMultipleChildrenDescendantsAndSelf();
|
||||
|
||||
var allVisibleNames = parentOfSubtractTargets.Children.Select(i => i.ID);
|
||||
// remove any names from SelectedChildren that are not a child we can select
|
||||
foreach (var name in selectableChildContainer.SelectedChildren.ToArray())
|
||||
{
|
||||
if (!allVisibleNames.Contains(name))
|
||||
{
|
||||
selectableChildContainer.SelectedChildren.Remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public IEnumerable<SceneOperation> GetOperations()
|
||||
{
|
||||
return PathObject3D.GetOperations(this.GetType());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue