diff --git a/PartPreviewWindow/View3D/Actions/SubtractAndReplace.cs b/PartPreviewWindow/View3D/Actions/SubtractAndReplace.cs index a53b76ecf..ca14d8f27 100644 --- a/PartPreviewWindow/View3D/Actions/SubtractAndReplace.cs +++ b/PartPreviewWindow/View3D/Actions/SubtractAndReplace.cs @@ -209,6 +209,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D if (paintObjects.Any() && keepObjects.Any()) { + var totalOperations = paintObjects.Count * keepObjects.Count; + double amountPerOperation = 1.0 / totalOperations; + double percentCompleted = 0; + foreach (var paint in paintObjects) { var transformedPaint = Mesh.Copy(paint.Mesh, cancellationToken); @@ -223,7 +227,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D transformedKeep.Transform(keep.WorldMatrix()); // remove the paint from the original - var intersectAndSubtract = PolygonMesh.Csg.CsgOperations.IntersectAndSubtract(transformedKeep, transformedPaint); + var intersectAndSubtract = PolygonMesh.Csg.CsgOperations.IntersectAndSubtract(transformedKeep, transformedPaint, (status, progress0To1) => + { + // Abort if flagged + cancellationToken.ThrowIfCancellationRequested(); + + progressStatus.Status = status; + progressStatus.Progress0To1 = percentCompleted + amountPerOperation * progress0To1; + reporter?.Report(progressStatus); + }, cancellationToken); var inverseKeep = keep.WorldMatrix(); inverseKeep.Invert(); intersectAndSubtract.subtract.Transform(inverseKeep); diff --git a/PartPreviewWindow/View3D/Actions/SubtractEditor.cs b/PartPreviewWindow/View3D/Actions/SubtractEditor.cs index 1a7a15e2e..3186760ce 100644 --- a/PartPreviewWindow/View3D/Actions/SubtractEditor.cs +++ b/PartPreviewWindow/View3D/Actions/SubtractEditor.cs @@ -216,12 +216,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D { progressStatus.Status = "Copy Remove"; reporter?.Report(progressStatus); - var transformedRemove = Mesh.Copy(remove.Mesh, CancellationToken.None); + var transformedRemove = Mesh.Copy(remove.Mesh, cancellationToken); transformedRemove.Transform(remove.WorldMatrix()); progressStatus.Status = "Copy Keep"; reporter?.Report(progressStatus); - var transformedKeep = Mesh.Copy(keep.Mesh, CancellationToken.None); + var transformedKeep = Mesh.Copy(keep.Mesh, cancellationToken); transformedKeep.Transform(keep.WorldMatrix()); progressStatus.Status = "Do CSG"; diff --git a/PrinterCommunication/PrinterConnection.cs b/PrinterCommunication/PrinterConnection.cs index feb5300f6..74c8b4e58 100644 --- a/PrinterCommunication/PrinterConnection.cs +++ b/PrinterCommunication/PrinterConnection.cs @@ -2466,7 +2466,9 @@ namespace MatterHackers.MatterControl.PrinterCommunication } // times up turn off heaters - if (ContinuWaitingToTurnOffHeaters) + if (ContinuWaitingToTurnOffHeaters + && !PrinterIsPrinting + && !PrinterIsPaused) { UiThread.RunOnIdle(() => { diff --git a/Submodules/MatterSlice b/Submodules/MatterSlice index 6cb7f7949..3ca863d64 160000 --- a/Submodules/MatterSlice +++ b/Submodules/MatterSlice @@ -1 +1 @@ -Subproject commit 6cb7f7949ccfc62096bf5a3cbedc39fe8fe56ece +Subproject commit 3ca863d643ff47053e74424efd13db13048c7892 diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index ed0cd4a86..39695a622 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit ed0cd4a8625acf26eb41cb45f430a03049ea577e +Subproject commit 39695a622650ffd4abdbe5de2921675104e94b78 diff --git a/Tests/MatterControl.Tests/MatterControl.Tests.csproj b/Tests/MatterControl.Tests/MatterControl.Tests.csproj index eae17513c..379af7542 100644 --- a/Tests/MatterControl.Tests/MatterControl.Tests.csproj +++ b/Tests/MatterControl.Tests/MatterControl.Tests.csproj @@ -127,6 +127,10 @@ {670BDDFF-927B-425D-9DD1-22ACB14356EB} PlatformWin32 + + {7ee4636d-8a92-4015-9562-7fcd6add0645} + Net3dBool + {86F6AAF2-9B50-40B8-A427-1897D76471C5} PolygonMesh diff --git a/Tests/MatterControl.Tests/MatterControl/MeshCsgTests.cs b/Tests/MatterControl.Tests/MatterControl/MeshCsgTests.cs index 44d98885b..47bdf5a9e 100644 --- a/Tests/MatterControl.Tests/MatterControl/MeshCsgTests.cs +++ b/Tests/MatterControl.Tests/MatterControl/MeshCsgTests.cs @@ -43,6 +43,7 @@ using MatterHackers.MatterControl.Tests.Automation; using MatterHackers.PolygonMesh.Csg; using MatterHackers.PolygonMesh.Processors; using MatterHackers.VectorMath; +using Net3dBool; using NUnit.Framework; namespace MatterHackers.PolygonMesh.UnitTests @@ -51,7 +52,7 @@ namespace MatterHackers.PolygonMesh.UnitTests public class MeshCsgTests { [Test] - public void CylinderMinusCylinder() + public void CsgCylinderMinusCylinder() { AggContext.StaticData = new FileSystemStaticData(TestContext.CurrentContext.ResolveProjectPath(4, "StaticData")); MatterControlUtilities.OverrideAppDataLocation(TestContext.CurrentContext.ResolveProjectPath(4)); @@ -61,66 +62,102 @@ namespace MatterHackers.PolygonMesh.UnitTests // check that we subtarct two 3 sideh cylinders { + double topHeight = 10; int sides = 3; - IObject3D keep = CylinderAdvancedObject3D.Create(20, 20, sides); - IObject3D subtract = CylinderAdvancedObject3D.Create(10, 20, sides); + IObject3D keep = CylinderAdvancedObject3D.Create(20, topHeight * 2, sides); + IObject3D subtract = CylinderAdvancedObject3D.Create(10, topHeight * 2, sides); var keepMesh = keep.Mesh; var subtractMesh = subtract.Mesh; - var split1 = new DebugFace() + if (false) { - EvaluateHeight = 10, - FileName = "Split1" - }; + var split1 = new DebugFace() + { + EvaluateHeight = topHeight, + FileName = "Split1" + }; - var resultMesh = keepMesh.Subtract(subtractMesh, null, CancellationToken.None);//, - //split1.Split, split1.Result); + BooleanModeller.Object1SplitFace = split1.Split; + BooleanModeller.Object1SplitResults = split1.Result; + + BooleanModeller.Object1ClassifyFace = split1.Classify1; + BooleanModeller.Object2ClassifyFace = split1.Classify2; + } + + var resultMesh = keepMesh.Subtract(subtractMesh, null, CancellationToken.None); // this is for debuging the opperation //split1.FinishOutput(); //resultMesh.Save("c:/temp/mesh1.stl", CancellationToken.None); - Assert.AreEqual(12, CountFacesAtHeight(keepMesh, 10)); + var topZero = new Vector3(0, 0, topHeight); + foreach (var topVertex in keepMesh.Vertices + .Where((v) => v.Position.Z == topHeight && v.Position != topZero) + .Select((gv) => gv.Position)) + { + Assert.IsTrue(resultMesh.Vertices.Where((v) => v.Position == topVertex).Any(), "Have all top vertexes"); + } + foreach (var topVertex in subtractMesh.Vertices + .Where((v) => v.Position.Z == topHeight && v.Position != topZero) + .Select((gv) => gv.Position)) + { + Assert.IsTrue(resultMesh.Vertices.Where((v) => v.Position == topVertex).Any(), "Have all top vertexes"); + } } // check that we subtarct two 3 sideh cylinders { int sides = 3; IObject3D keep = CylinderAdvancedObject3D.Create(20, 20, sides); - IObject3D subtract = CylinderAdvancedObject3D.Create(10, 21, sides); + IObject3D subtract = CylinderAdvancedObject3D.Create(10, 22, sides); var keepMesh = keep.Mesh; var subtractMesh = subtract.Mesh; - var split1 = new DebugFace() + if (false) { - EvaluateHeight = 10, - FileName = "Split2" - }; + var split1 = new DebugFace() + { + EvaluateHeight = 10, + FileName = "Split2" + }; - var resultMesh = keepMesh.Subtract(subtractMesh, null, CancellationToken.None);//, - //split1.Split, split1.Result); + BooleanModeller.Object1SplitFace = split1.Split; + BooleanModeller.Object1SplitResults = split1.Result; + } + + var resultMesh = keepMesh.Subtract(subtractMesh, null, CancellationToken.None); // this is for debuging the opperation //split1.FinishOutput(); - //esultMesh.Save("c:/temp/mesh2.stl", CancellationToken.None); + //resultMesh.Save("c:/temp/mesh2.stl", CancellationToken.None); - Assert.AreEqual(12, CountFacesAtHeight(keepMesh, 10)); + foreach (var topVertex in keepMesh.Vertices + .Where((v) => v.Position.Z == 10 && v.Position != new Vector3(0, 0, 10)) + .Select((gv) => gv.Position)) + { + Assert.IsTrue(resultMesh.Vertices.Where((v) => v.Position == topVertex).Any(), "Have all top vertexes"); + } + foreach (var topVertex in subtractMesh.Vertices + .Where((v) => v.Position.Z == 11 && v.Position != new Vector3(0, 0, 11)) + .Select((gv) => gv.Position)) + { + Assert.IsTrue(resultMesh.Vertices + .Where((v) => v.Position.Equals(new Vector3(topVertex.X, topVertex.Y, 10), .0001)) + .Any(), "Have all top vertexes"); + } } } - - private double CountFacesAtHeight(Mesh keepMesh, double zHeightToFind) - { - // TODO: make this work - return 12; - } } public class DebugFace { private int currentIndex; - private StringBuilder allPolygonDebug = new StringBuilder(); + private StringBuilder allSplitPolygonDebug = new StringBuilder(); + private StringBuilder allResultsPolygonDebug = new StringBuilder(); + private StringBuilder classifiedFaces1 = new StringBuilder(); + private StringBuilder classifiedFaces2 = new StringBuilder(); private StringBuilder htmlContent = new StringBuilder(); private StringBuilder individualPolygonDebug = new StringBuilder(); @@ -131,7 +168,7 @@ namespace MatterHackers.PolygonMesh.UnitTests Vector2 offset = new Vector2(10, 18); double scale = 13; - public void Result(List splitResults) + public void Result(List splitResults) { if (splitResults.Count > 0 && FaceAtHeight(splitResults[0], EvaluateHeight)) @@ -141,19 +178,17 @@ namespace MatterHackers.PolygonMesh.UnitTests foreach (var face in splitResults) { individualPolygonDebug.AppendLine(GetCoords(face)); + allResultsPolygonDebug.AppendLine(GetCoords(face)); } individualPolygonDebug.AppendLine(""); } } - public void Split(Vector3[] faceToSplit, Vector3[] splitAtFace) + public void Split(CsgFace faceToSplit, CsgFace splitAtFace) { if (FaceAtHeight(faceToSplit, EvaluateHeight)) { - string faceToSplitCoords = GetCoords(faceToSplit); - string splitAtFaceCoords = GetCoords(splitAtFace); - - allPolygonDebug.AppendLine(faceToSplitCoords); + allSplitPolygonDebug.AppendLine(GetCoords(faceToSplit)); if (currentIndex == 0) { @@ -166,22 +201,32 @@ namespace MatterHackers.PolygonMesh.UnitTests currentIndex++; individualPolygonDebug.AppendLine($"
{currentIndex}
"); individualPolygonDebug.AppendLine($""); - individualPolygonDebug.AppendLine(faceToSplitCoords); - individualPolygonDebug.AppendLine(splitAtFaceCoords); + individualPolygonDebug.AppendLine(GetCoords(faceToSplit)); + individualPolygonDebug.AppendLine(GetCoords(splitAtFace)); individualPolygonDebug.AppendLine(""); } } public void FinishOutput() { - htmlContent.AppendLine($""); - - htmlContent.Append(allPolygonDebug.ToString()); + htmlContent.AppendLine($""); + htmlContent.Append(allSplitPolygonDebug.ToString()); + htmlContent.AppendLine(""); + htmlContent.AppendLine($""); + htmlContent.Append(allResultsPolygonDebug.ToString()); htmlContent.AppendLine(""); htmlContent.Append(individualPolygonDebug.ToString()); + htmlContent.AppendLine($""); + htmlContent.Append(classifiedFaces1.ToString()); + htmlContent.AppendLine(""); + + htmlContent.AppendLine($""); + htmlContent.Append(classifiedFaces2.ToString()); + htmlContent.AppendLine(""); + htmlContent.AppendLine(""); htmlContent.AppendLine(""); @@ -199,19 +244,19 @@ namespace MatterHackers.PolygonMesh.UnitTests return false; } - public static bool FaceAtHeight(Vector3[] face, double height) + public static bool FaceAtHeight(CsgFace face, double height) { - if (!AreEqual(face[0].Z, height)) + if (!AreEqual(face.v1.Position.Z, height)) { return false; } - if (!AreEqual(face[1].Z, height)) + if (!AreEqual(face.v2.Position.Z, height)) { return false; } - if (!AreEqual(face[2].Z, height)) + if (!AreEqual(face.v3.Position.Z, height)) { return false; } @@ -242,15 +287,20 @@ namespace MatterHackers.PolygonMesh.UnitTests return true; } - public string GetCoords(Vector3[] face) + public string GetCoords(CsgFace face) { - Vector2 p1 = (new Vector2(face[0].X, -face[0].Y) + offset) * scale; - Vector2 p2 = (new Vector2(face[1].X, -face[1].Y) + offset) * scale; - Vector2 p3 = (new Vector2(face[2].X, -face[2].Y) + offset) * scale; + return GetCoords(face, Color.Black, new Color(Color.Red, 100)); + } + + public string GetCoords(CsgFace face, Color strokeColor, Color fillColor, double lineWidth = 1) + { + Vector2 p1 = (new Vector2(face.v1.Position.X, -face.v1.Position.Y) + offset) * scale; + Vector2 p2 = (new Vector2(face.v2.Position.X, -face.v2.Position.Y) + offset) * scale; + Vector2 p3 = (new Vector2(face.v3.Position.X, -face.v3.Position.Y) + offset) * scale; string coords = $"{p1.X:0.0}, {p1.Y:0.0}"; coords += $", {p2.X:0.0}, {p2.Y:0.0}"; coords += $", {p3.X:0.0}, {p3.Y:0.0}"; - return $""; + return $""; } public static bool HasPosition(Vector3[] face, Vector3 position) @@ -270,5 +320,77 @@ namespace MatterHackers.PolygonMesh.UnitTests return false; } + + public void Classify1(CsgFace face) + { + //if (FaceAtHeight(face, EvaluateHeight)) + { + Color color = new Color(); + switch (face.Status) + { + case FaceStatus.Unknown: + color = Color.Cyan; + break; + case FaceStatus.Inside: + color = Color.Green; + break; + case FaceStatus.Outside: + color = Color.Red; + break; + case FaceStatus.Same: + color = Color.Gray; + break; + case FaceStatus.Opposite: + color = Color.Yellow; + break; + case FaceStatus.Boundary: + color = Color.Indigo; + break; + default: + throw new NotImplementedException(); + } + + // make it transparent + color = new Color(color, 100); + + classifiedFaces1.AppendLine(GetCoords(face, Color.Black, color)); + } + } + + public void Classify2(CsgFace face) + { + if (FaceAtHeight(face, EvaluateHeight)) + { + Color color = new Color(); + switch (face.Status) + { + case FaceStatus.Unknown: + color = Color.Cyan; + break; + case FaceStatus.Inside: + color = Color.Green; + break; + case FaceStatus.Outside: + color = Color.Red; + break; + case FaceStatus.Same: + color = Color.Gray; + break; + case FaceStatus.Opposite: + color = Color.Yellow; + break; + case FaceStatus.Boundary: + color = Color.Indigo; + break; + default: + throw new NotImplementedException(); + } + + // make it transparent + color = new Color(color, 100); + + classifiedFaces2.AppendLine(GetCoords(face, Color.Black, color)); + } + } } } \ No newline at end of file