private void Intersect(CancellationToken cancellationToken, IProgress <ProgressStatus> 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 first = participants.First(); var resultsMesh = first.Mesh; var firstWorldMatrix = first.WorldMatrix(SourceContainer); var totalOperations = participants.Count() - 1; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; ProgressStatus progressStatus = new ProgressStatus(); foreach (var item in participants) { if (item != first) { var itemWorldMatrix = item.WorldMatrix(SourceContainer); resultsMesh = BooleanProcessing.Do(item.Mesh, itemWorldMatrix, resultsMesh, firstWorldMatrix, 2, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); // after the first union we are working with the transformed mesh and don't need the first transform firstWorldMatrix = Matrix4X4.Identity; percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; reporter?.Report(progressStatus); } } var resultsItem = new Object3D() { Mesh = resultsMesh }; resultsItem.CopyProperties(first, Object3DPropertyFlags.All & (~Object3DPropertyFlags.Matrix)); this.Children.Add(resultsItem); SourceContainer.Visible = false; }
public void Combine(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { ResetMeshWrapperMeshes(Object3DPropertyFlags.All, cancellationToken); var participants = this.Descendants().Where(o => o.OwnerID == this.ID).ToList(); if (participants.Count() < 2) { return; } var first = participants.First(); var totalOperations = participants.Count() - 1; double amountPerOperation = 1.0 / totalOperations; double ratioCompleted = 0; ProgressStatus progressStatus = new ProgressStatus(); foreach (var item in participants) { if (item != first) { var result = BooleanProcessing.Do(item.Mesh, item.WorldMatrix(), first.Mesh, first.WorldMatrix(), CsgModes.Union, ProcessingModes.Polygons, ProcessingResolution._64, ProcessingResolution._64, reporter, amountPerOperation, ratioCompleted, progressStatus, cancellationToken); var inverse = first.WorldMatrix(); inverse.Invert(); result.Transform(inverse); using (first.RebuildLock()) { first.Mesh = result; } ratioCompleted += amountPerOperation; progressStatus.Progress0To1 = ratioCompleted; reporter?.Report(progressStatus); } } }
private void Intersect(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { ResetMeshWrapperMeshes(Object3DPropertyFlags.All, cancellationToken); var participants = this.DescendantsAndSelf().Where((obj) => obj.OwnerID == this.ID); if (participants.Count() > 1) { var first = participants.First(); var totalOperations = participants.Count() - 1; double amountPerOperation = 1.0 / totalOperations; double ratioCompleted = 0; ProgressStatus progressStatus = new ProgressStatus(); foreach (var remove in participants) { if (remove != first) { var result = BooleanProcessing.Do(remove.Mesh, remove.WorldMatrix(), first.Mesh, first.WorldMatrix(), CsgModes.Intersect, ProcessingModes.Polygons, ProcessingResolution._64, ProcessingResolution._64, reporter, amountPerOperation, ratioCompleted, progressStatus, cancellationToken); var inverse = first.WorldMatrix(); inverse.Invert(); result.Transform(inverse); using (first.RebuildLock()) { first.Mesh = result; } remove.Visible = false; ratioCompleted += amountPerOperation; progressStatus.Progress0To1 = ratioCompleted; reporter.Report(progressStatus); } } } }
public static void Subtract(List <IObject3D> keepObjects, List <IObject3D> removeObjects, CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { if (removeObjects.Any() && keepObjects.Any()) { var totalOperations = removeObjects.Count * keepObjects.Count; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; 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 = "Copy Remove"; reporter?.Report(progressStatus); var transformedRemove = remove.obj3D.Mesh.Copy(cancellationToken); transformedRemove.Transform(remove.matrix); progressStatus.Status = "Copy Keep"; reporter?.Report(progressStatus); var transformedKeep = keep.obj3D.Mesh.Copy(cancellationToken); transformedKeep.Transform(keep.matrix); progressStatus.Status = "Do CSG"; reporter?.Report(progressStatus); var result = BooleanProcessing.Do(transformedKeep, transformedRemove, 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var inverse = keep.matrix.Inverted; result.Transform(inverse); using (keep.obj3D.RebuildLock()) { keep.obj3D.Mesh = result; } percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; reporter?.Report(progressStatus); } remove.obj3D.Visible = false; } } }
private void Combine(CancellationToken cancellationToken, IProgress <ProgressStatus> 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 items = participants.Select(i => (i.Mesh, i.WorldMatrix(SourceContainer))); var resultsMesh = BooleanProcessing.DoArray(items, BooleanProcessing.CsgModes.Union, Processing, InputResolution, OutputResolution, reporter, cancellationToken); var resultsItem = new Object3D() { Mesh = resultsMesh }; resultsItem.CopyProperties(participants.First(), Object3DPropertyFlags.All & (~Object3DPropertyFlags.Matrix)); this.Children.Add(resultsItem); SourceContainer.Visible = false; }
public static void Combine(List <IObject3D> participants, CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { var first = participants.First(); var totalOperations = participants.Count() - 1; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; ProgressStatus progressStatus = new ProgressStatus(); foreach (var item in participants) { if (item != first) { var transformedRemove = item.Mesh.Copy(CancellationToken.None); transformedRemove.Transform(item.WorldMatrix()); var transformedKeep = first.Mesh.Copy(CancellationToken.None); transformedKeep.Transform(first.WorldMatrix()); var result = BooleanProcessing.Do(transformedKeep, transformedRemove, 0, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var inverse = first.WorldMatrix(); inverse.Invert(); result.Transform(inverse); using (first.RebuildLock()) { first.Mesh = result; } item.Visible = false; percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; reporter.Report(progressStatus); } } }
private void SubtractAndReplace(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { SourceContainer.Visible = true; RemoveAllButSource(); var parentOfPaintTargets = SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf(); if (parentOfPaintTargets.Children.Count() < 2) { if (parentOfPaintTargets.Children.Count() == 1) { this.Children.Add(SourceContainer.Clone()); SourceContainer.Visible = false; } return; } SubtractObject3D_2.CleanUpSelectedChildrenNames(this); 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 keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList(); if (paintObjects.Any() && keepVisibleItems.Any()) { var totalOperations = paintObjects.Count * keepVisibleItems.Count; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; var progressStatus = new ProgressStatus { Status = "Do CSG" }; foreach (var keep in keepVisibleItems) { var keepResultsMesh = keep.Mesh; var keepWorldMatrix = keep.WorldMatrix(SourceContainer); foreach (var paint in paintObjects) { Mesh paintMesh = BooleanProcessing.Do(keepResultsMesh, keepWorldMatrix, // paint data paint.Mesh, paint.WorldMatrix(SourceContainer), // operation type 2, // reporting data reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); keepResultsMesh = BooleanProcessing.Do(keepResultsMesh, keepWorldMatrix, // point data paint.Mesh, paint.WorldMatrix(SourceContainer), // operation type 1, // reporting data reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); // 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); // report our progress percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; 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); } foreach (var child in Children) { child.Visible = true; } SourceContainer.Visible = false; } }
private void Rebuild(UndoBuffer undoBuffer) { var rebuildLock = RebuildLock(); ResetMeshWrapperMeshes(Object3DPropertyFlags.All, CancellationToken.None); ApplicationController.Instance.Tasks.Execute("Intersection".Localize(), (reporter, cancellationToken) => { var progressStatus = new ProgressStatus(); var participants = this.DescendantsAndSelf().Where((obj) => obj.OwnerID == this.ID); try { if (participants.Count() > 1) { var first = participants.First(); var totalOperations = participants.Count() - 1; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; foreach (var remove in participants) { if (remove != first) { var transformedRemove = remove.Mesh.Copy(CancellationToken.None); transformedRemove.Transform(remove.WorldMatrix()); var transformedKeep = first.Mesh.Copy(CancellationToken.None); transformedKeep.Transform(first.WorldMatrix()); var result = BooleanProcessing.Do(transformedKeep, transformedRemove, 2, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var inverse = first.WorldMatrix(); inverse.Invert(); result.Transform(inverse); using (first.RebuildLock()) { first.Mesh = result; } remove.Visible = false; percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; reporter.Report(progressStatus); } } } } catch { } UiThread.RunOnIdle(() => { rebuildLock.Dispose(); base.Invalidate(new InvalidateArgs(this, InvalidateType.Content)); }); return(Task.CompletedTask); }); }
public void Subtract(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { ResetMeshWrapperMeshes(Object3DPropertyFlags.All, cancellationToken); bool ItemInSubtractList(IObject3D item) { if (ItemsToSubtract.Contains(item.ID)) { return(true); } // check if the wrapped item is in the subtract list if (item.Children.Count > 0 && ItemsToSubtract.Contains(item.Children.First().ID)) { return(true); } 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(); if (removeObjects.Any() && keepObjects.Any()) { var totalOperations = removeObjects.Count * keepObjects.Count; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; 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 = "Copy Remove"; reporter?.Report(progressStatus); progressStatus.Status = "Copy Keep"; reporter?.Report(progressStatus); progressStatus.Status = "Do CSG"; reporter?.Report(progressStatus); var result = BooleanProcessing.Do(keep.obj3D.Mesh, keep.matrix, remove.obj3D.Mesh, remove.matrix, 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var inverse = keep.matrix.Inverted; result.Transform(inverse); using (keep.obj3D.RebuildLock()) { keep.obj3D.Mesh = result; } percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; reporter?.Report(progressStatus); } remove.obj3D.Visible = false; } } }
private void Subtract(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { SourceContainer.Visible = true; RemoveAllButSource(); var parentOfSubtractTargets = SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf(); if (parentOfSubtractTargets.Children.Count() < 2) { if (parentOfSubtractTargets.Children.Count() == 1) { this.Children.Add(SourceContainer.Clone()); SourceContainer.Visible = false; } return; } CleanUpSelectedChildrenNames(this); var removeVisibleItems = parentOfSubtractTargets.Children .Where((i) => SelectedChildren .Contains(i.Name)) .SelectMany(c => c.VisibleMeshes()) .ToList(); var keepItems = parentOfSubtractTargets.Children .Where((i) => !SelectedChildren .Contains(i.Name)); var keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList(); if (removeVisibleItems.Any() && keepVisibleItems.Any()) { var totalOperations = removeVisibleItems.Count * keepVisibleItems.Count; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; ProgressStatus progressStatus = new ProgressStatus(); progressStatus.Status = "Do CSG"; foreach (var keep in keepVisibleItems) { var resultsMesh = keep.Mesh; var keepWorldMatrix = keep.WorldMatrix(SourceContainer); foreach (var remove in removeVisibleItems) { resultsMesh = BooleanProcessing.Do(resultsMesh, keepWorldMatrix, remove.Mesh, remove.WorldMatrix(SourceContainer), 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); // after the first time we get a result the results mesh is in the right coordinate space keepWorldMatrix = Matrix4X4.Identity; // report our progress percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; reporter?.Report(progressStatus); } // store our results mesh var resultsItem = new Object3D() { Mesh = resultsMesh, Visible = false }; // copy all the properties but the matrix resultsItem.CopyWorldProperties(keep, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible))); // and add it to this this.Children.Add(resultsItem); } bool first = true; foreach (var child in Children) { if (first) { // hid the source item child.Visible = false; first = false; } else { child.Visible = true; } } } }
public void SubtractAndReplace(CancellationToken cancellationToken, IProgress <ProgressStatus> 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(); if (paintObjects.Any() && keepObjects.Any()) { var totalOperations = paintObjects.Count * keepObjects.Count; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 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; 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); // remove the paint from the original var subtract = BooleanProcessing.Do(keep.obj3D.Mesh, keep.matrix, paint.obj3D.Mesh, paint.matrix, 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var intersect = BooleanProcessing.Do(keep.obj3D.Mesh, keep.matrix, paint.obj3D.Mesh, paint.matrix, 2, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var inverseKeep = keep.matrix.Inverted; subtract.Transform(inverseKeep); using (keep.obj3D.RebuildLock()) { keep.obj3D.Mesh = subtract; } // 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, 0, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); } if (cancellationToken.IsCancellationRequested) { break; } } // move the paint mesh back to its original coordinates paintMesh.Transform(inverseRemove); using (paint.obj3D.RebuildLock()) { paint.obj3D.Mesh = paintMesh; } paint.obj3D.Color = paint.obj3D.WorldColor().WithContrast(keepObjects.First().WorldColor(), 2).ToColor(); } } }
private void SubtractAndReplace(CancellationToken cancellationToken, IProgress <ProgressStatus> 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; } SubtractObject3D_2.CleanUpSelectedChildrenNames(this); var paintObjects = this.SourceContainer.VisibleMeshes() .Where((i) => SelectedChildren.Contains(i.Name)).ToList(); var keepObjects = this.SourceContainer.VisibleMeshes() .Where((i) => !SelectedChildren.Contains(i.Name)).ToList(); if (paintObjects.Any() && keepObjects.Any()) { var totalOperations = paintObjects.Count * keepObjects.Count; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; ProgressStatus progressStatus = new ProgressStatus(); progressStatus.Status = "Do CSG"; foreach (var keep in keepObjects) { var keepResultsMesh = keep.Mesh; var keepWorldMatrix = keep.WorldMatrix(SourceContainer); foreach (var paint in paintObjects) { Mesh paintMesh = BooleanProcessing.Do(keepResultsMesh, keepWorldMatrix, paint.Mesh, paint.WorldMatrix(SourceContainer), 2, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); keepResultsMesh = BooleanProcessing.Do(keepResultsMesh, keepWorldMatrix, paint.Mesh, paint.WorldMatrix(SourceContainer), 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); // 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 }; // copy all the properties but the matrix paintResultsItem.CopyProperties(paint, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible))); // and add it to this this.Children.Add(paintResultsItem); // report our progress percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; reporter?.Report(progressStatus); } // store our results mesh var keepResultsItem = new Object3D() { Mesh = keepResultsMesh, Visible = false }; // copy all the properties but the matrix keepResultsItem.CopyProperties(keep, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible))); // and add it to this this.Children.Add(keepResultsItem); } foreach (var child in Children) { child.Visible = true; } SourceContainer.Visible = false; } }
private void Intersect(CancellationToken cancellationToken, IProgress <ProgressStatus> 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 items = participants.Select(i => (i.Mesh, i.WorldMatrix(SourceContainer))); #if false var resultsMesh = BooleanProcessing.DoArray(items, CsgModes.Intersect, Processing, InputResolution, OutputResolution, reporter, cancellationToken); #else 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; 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, progressStatus, cancellationToken); // 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); } #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; } }
private void Rebuild(UndoBuffer undoBuffer) { this.DebugDepth("Rebuild"); var rebuildLock = RebuildLock(); ResetMeshWrapperMeshes(Object3DPropertyFlags.All, CancellationToken.None); // spin up a task to calculate the paint ApplicationController.Instance.Tasks.Execute("Subtract".Localize(), (reporter, cancellationToken) => { var progressStatus = new ProgressStatus(); 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(); try { if (paintObjects.Any() && keepObjects.Any()) { var totalOperations = paintObjects.Count * keepObjects.Count; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 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 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(transformedKeep, transformedPaint, 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var intersect = BooleanProcessing.Do(transformedKeep, transformedPaint, 2, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var inverseKeep = keep.matrix.Inverted; subtract.Transform(inverseKeep); using (keep.obj3D.RebuildLock()) { keep.obj3D.Mesh = subtract; } // keep all the intersections together if (paintMesh == null) { paintMesh = intersect; } else // union into the current paint { paintMesh = BooleanProcessing.Do(transformedKeep, intersect, 0, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); } if (cancellationToken.IsCancellationRequested) { break; } } // move the paint mesh back to its original coordinates paintMesh.Transform(inverseRemove); using (paint.obj3D.RebuildLock()) { paint.obj3D.Mesh = paintMesh; } paint.obj3D.Color = paint.obj3D.WorldColor().WithContrast(keepObjects.First().WorldColor(), 2).ToColor(); } }
private void Subtract(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { SourceContainer.Visible = true; RemoveAllButSource(); var parentOfSubtractTargets = SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf(); if (parentOfSubtractTargets.Children.Count() < 2) { if (parentOfSubtractTargets.Children.Count() == 1) { this.Children.Add(SourceContainer.Clone()); SourceContainer.Visible = false; } return; } CleanUpSelectedChildrenNames(this); var removeVisibleItems = parentOfSubtractTargets.Children .Where((i) => SelectedChildren .Contains(i.ID)) .SelectMany(c => c.VisibleMeshes()) .ToList(); var keepItems = parentOfSubtractTargets.Children .Where((i) => !SelectedChildren .Contains(i.ID)); var keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList(); if (removeVisibleItems.Any() && keepVisibleItems.Any()) { foreach (var keep in keepVisibleItems) { #if false var items = removeVisibleItems.Select(i => (i.Mesh, i.WorldMatrix(SourceContainer))).ToList(); items.Insert(0, (keep.Mesh, keep.Matrix)); var resultsMesh = BooleanProcessing.DoArray(items, CsgModes.Subtract, Processing, InputResolution, OutputResolution, reporter, cancellationToken); #else var totalOperations = removeVisibleItems.Count * keepVisibleItems.Count; double amountPerOperation = 1.0 / totalOperations; double ratioCompleted = 0; var progressStatus = new ProgressStatus { Status = "Do CSG" }; var resultsMesh = keep.Mesh; var keepWorldMatrix = keep.WorldMatrix(SourceContainer); foreach (var remove in removeVisibleItems) { resultsMesh = BooleanProcessing.Do(resultsMesh, keepWorldMatrix, // other mesh remove.Mesh, remove.WorldMatrix(SourceContainer), // operation type CsgModes.Subtract, 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; // report our progress ratioCompleted += amountPerOperation; progressStatus.Progress0To1 = ratioCompleted; reporter?.Report(progressStatus); } #endif // store our results mesh var resultsItem = new Object3D() { Mesh = resultsMesh, Visible = false, OwnerID = keep.ID }; // copy all the properties but the matrix resultsItem.CopyWorldProperties(keep, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible))); // and add it to this this.Children.Add(resultsItem); if (!RemoveSubtractObjects) { this.Children.Modify((list) => { foreach (var item in removeVisibleItems) { var newObject = new Object3D() { Mesh = item.Mesh }; newObject.CopyWorldProperties(item, SourceContainer, Object3DPropertyFlags.All & (~Object3DPropertyFlags.Visible)); list.Add(newObject); } }); } } bool first = true; foreach (var child in Children) { if (first) { // hide the source item child.Visible = false; first = false; } else { child.Visible = true; } } } }