public void CorrectRayOnCircle() { var testPartPath = TestContext.CurrentContext.ResolveProjectPath(new string[] { "..", "..", "..", "examples", "RayTracerTest" }); var testPart = Path.Combine(testPartPath, "circle_100x100_centered.stl"); Mesh simpleMesh = StlProcessing.Load(testPart, CancellationToken.None); var bvhCollection = MeshToBVH.Convert(simpleMesh); var scene = new Scene(); scene.shapes.Add(bvhCollection); RayTracer raytracer = new RayTracer() { AntiAliasing = AntiAliasing.None, MultiThreaded = false, }; int samples = 40; var advance = MathHelper.Tau / samples; TestSingleAngle(scene, raytracer, advance, 15); for (int i = 0; i < samples; i++) { TestSingleAngle(scene, raytracer, advance, i); } }
public void SliceLayersGeneratingCorrectSegments() { // TODO: Make tests work on Mac as well as Windows if (OsInformation.OperatingSystem == OSType.Mac) { return; } string pathToMesh = Path.Combine("..", "..", "..", "TestData", "TestMeshes", "SliceLayers"); string meshFileName = Path.Combine(pathToMesh, "Box20x20x10.stl"); Mesh cubeMesh = StlProcessing.Load(meshFileName); AxisAlignedBoundingBox bounds = cubeMesh.GetAxisAlignedBoundingBox(); Assert.IsTrue(bounds.ZSize == 10); SliceLayers layers = new SliceLayers(); layers.GetPerimetersForAllLayers(cubeMesh, .2, .2); Assert.IsTrue(layers.AllLayers.Count == 50); foreach (SliceLayer layer in layers.AllLayers) { Assert.IsTrue(layer.UnorderedSegments.Count == 8); // work in progress //Assert.IsTrue(layer.Perimeters.Count == 1); //Assert.IsTrue(layer.Perimeters[0].Count == 8); } layers.GetPerimetersForAllLayers(cubeMesh, .2, .1); Assert.IsTrue(layers.AllLayers.Count == 99); }
//[Test] public void SliceLayersGeneratingCorrectSegments() { // TODO: Make tests work on Mac as well as Windows if (AggContext.OperatingSystem == OSType.Mac) { return; } string meshFileName = TestContext.CurrentContext.ResolveProjectPath(4, "Tests", "TestData", "TestMeshes", "SliceLayers", "Box20x20x10.stl"); Mesh cubeMesh = StlProcessing.Load(meshFileName, CancellationToken.None); AxisAlignedBoundingBox bounds = cubeMesh.GetAxisAlignedBoundingBox(); Assert.IsTrue(bounds.ZSize == 10); SliceLayers layers = new SliceLayers(); layers.GetPerimetersForAllLayers(cubeMesh, .2, .2); Assert.IsTrue(layers.AllLayers.Count == 50); foreach (SliceLayer layer in layers.AllLayers) { Assert.IsTrue(layer.UnorderedSegments.Count == 8); // work in progress //Assert.IsTrue(layer.Perimeters.Count == 1); //Assert.IsTrue(layer.Perimeters[0].Count == 8); } layers.GetPerimetersForAllLayers(cubeMesh, .2, .1); Assert.IsTrue(layers.AllLayers.Count == 99); }
private void AddTestStl() { Stopwatch loadTime = new Stopwatch(); loadTime.Start(); PolygonMesh.Mesh simpleMesh = StlProcessing.Load("Simple.stl"); //PolygonMesh.Mesh simpleMesh = StlProcessing.Load("Complex.stl"); //PolygonMesh.Mesh simpleMesh = StlProcessing.Load("bunny.stl"); //PolygonMesh.Mesh simpleMesh = StlProcessing.Load("bunny_binary.stl"); loadTime.Stop(); timingStrings.Add("Time to load STL {0:0.0}s".FormatWith(loadTime.Elapsed.TotalSeconds)); Stopwatch bvhTime = new Stopwatch(); bvhTime.Start(); IPrimitive bvhCollection = MeshToBVH.Convert(simpleMesh); bvhTime.Stop(); timingStrings.Add("Time to create BVH {0:0.0}s".FormatWith(bvhTime.Elapsed.TotalSeconds)); renderCollection.Add(bvhCollection); }
void createThumbnailWorker_DoWork(object sender, DoWorkEventArgs e) { PartThumbnailWidget thumbnailWidget = e.Argument as PartThumbnailWidget; if (thumbnailWidget != null) { if (thumbnailWidget.printItem == null) { thumbnailWidget.image = new ImageBuffer(thumbnailWidget.noThumbnailImage); } else // generate the image { Mesh loadedMesh = StlProcessing.Load(thumbnailWidget.printItem.FileLocation); thumbnailWidget.image = new ImageBuffer(thumbnailWidget.buildingThumbnailImage); thumbnailWidget.Invalidate(); if (loadedMesh != null) { ImageBuffer tempImage = new ImageBuffer(thumbnailWidget.image.Width, thumbnailWidget.image.Height, 32, new BlenderBGRA()); Graphics2D partGraphics2D = tempImage.NewGraphics2D(); List <MeshEdge> nonManifoldEdges = loadedMesh.GetNonManifoldEdges(); if (nonManifoldEdges.Count > 0) { if (File.Exists("RunUnitTests.txt")) { partGraphics2D.Circle(4, 4, 4, RGBA_Bytes.Red); } } nonManifoldEdges = null; AxisAlignedBoundingBox aabb = loadedMesh.GetAxisAlignedBoundingBox(); double maxSize = Math.Max(aabb.XSize, aabb.YSize); double scale = thumbnailWidget.image.Width / (maxSize * 1.2); RectangleDouble bounds2D = new RectangleDouble(aabb.minXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.x, aabb.maxXYZ.y); PolygonMesh.Rendering.OrthographicZProjection.DrawTo(partGraphics2D, loadedMesh, new Vector2((thumbnailWidget.image.Width / scale - bounds2D.Width) / 2 - bounds2D.Left, (thumbnailWidget.image.Height / scale - bounds2D.Height) / 2 - bounds2D.Bottom), scale, thumbnailWidget.FillColor); thumbnailWidget.image = new ImageBuffer(tempImage); loadedMesh = new Mesh(); } else { thumbnailWidget.image = new ImageBuffer(thumbnailWidget.noThumbnailImage); } } thumbnailWidget.Invalidate(); } }
public LogoSpinner(GuiWidget widget, double scale = 1.6, double spinSpeed = 0.6, double yOffset = 0.5, double rotateX = -0.1) { // loading animation stuff LightingData lighting = new LightingData(); Mesh logoMesh; using (var logoStream = StaticData.Instance.OpenStream(Path.Combine("Stls", "MH Logo.stl"))) { logoMesh = StlProcessing.Load(logoStream, CancellationToken.None); } // Position var aabb = logoMesh.GetAxisAlignedBoundingBox(); logoMesh.Transform(Matrix4X4.CreateTranslation(-aabb.Center)); logoMesh.Transform(Matrix4X4.CreateScale(scale / aabb.XSize)); var anglePerDraw = 1 / MathHelper.Tau * spinSpeed; var angle = 0.0; widget.BeforeDraw += (s, e) => { var screenSpaceBounds = widget.TransformToScreenSpace(widget.LocalBounds); WorldView world = new WorldView(screenSpaceBounds.Width, screenSpaceBounds.Height); world.Translate(new Vector3(0, yOffset, 0)); world.Rotate(Quaternion.FromEulerAngles(new Vector3(rotateX, 0, 0))); GLHelper.SetGlContext(world, screenSpaceBounds, lighting); GLHelper.Render(logoMesh, this.MeshColor, Matrix4X4.CreateRotationY(angle), RenderTypes.Shaded); GLHelper.UnsetGlContext(); }; Animation spinAnimation = new Animation() { DrawTarget = widget, FramesPerSecond = 20 }; spinAnimation.Update += (s, time) => { if (this.SpinLogo) { angle += anglePerDraw; } }; spinAnimation.Start(); }
private void LoadStl_Click(object sender, EventArgs e) { OpenFileDialogParams opeParams = new OpenFileDialogParams("STL Files|*.stl"); FileDialog.OpenFileDialog(opeParams, (openParams) => { var streamToLoadFrom = File.Open(openParams.FileName, FileMode.Open); if (streamToLoadFrom != null) { var loadedFileName = openParams.FileName; meshToRender = StlProcessing.Load(streamToLoadFrom); ImageBuffer plateInventory = new ImageBuffer((int)(300 * 8.5), 300 * 11, 32, new BlenderBGRA()); Graphics2D plateGraphics = plateInventory.NewGraphics2D(); plateGraphics.Clear(RGBA_Bytes.White); double inchesPerMm = 0.0393701; double pixelsPerInch = 300; double pixelsPerMm = inchesPerMm * pixelsPerInch; AxisAlignedBoundingBox aabb = meshToRender.GetAxisAlignedBoundingBox(); Vector2 lowerLeftInMM = new Vector2(-aabb.minXYZ.x, -aabb.minXYZ.y); Vector3 centerInMM = (aabb.maxXYZ - aabb.minXYZ) / 2; Vector2 offsetInMM = new Vector2(20, 30); { RectangleDouble bounds = new RectangleDouble(offsetInMM.x * pixelsPerMm, offsetInMM.y * pixelsPerMm, (offsetInMM.x + aabb.maxXYZ.x - aabb.minXYZ.x) * pixelsPerMm, (offsetInMM.y + aabb.maxXYZ.y - aabb.minXYZ.y) * pixelsPerMm); bounds.Inflate(3 * pixelsPerMm); RoundedRect rect = new RoundedRect(bounds, 3 * pixelsPerMm); plateGraphics.Render(rect, RGBA_Bytes.LightGray); Stroke rectOutline = new Stroke(rect, .5 * pixelsPerMm); plateGraphics.Render(rectOutline, RGBA_Bytes.DarkGray); } OrthographicZProjection.DrawTo(plateGraphics, meshToRender, lowerLeftInMM + offsetInMM, pixelsPerMm); plateGraphics.DrawString(Path.GetFileName(openParams.FileName), (offsetInMM.x + centerInMM.x) * pixelsPerMm, (offsetInMM.y - 10) * pixelsPerMm, 50, Agg.Font.Justification.Center); //ImageBuffer logoImage = new ImageBuffer(); //ImageIO.LoadImageData("Logo.png", logoImage); //plateGraphics.Render(logoImage, (plateInventory.Width - logoImage.Width) / 2, plateInventory.Height - logoImage.Height - 10 * pixelsPerMm); //ImageIO.SaveImageData("plate Inventory.jpeg", plateInventory); } }); }
public MeasureToolObject3D() { Name = "Measure Tool".Localize(); Color = Color.FromHSL(.11, .98, .76); if (shape == null) { using (Stream measureAmfStream = StaticData.Instance.OpenStream(Path.Combine("Stls", "measure_tool.stl"))) { shape = StlProcessing.Load(measureAmfStream, CancellationToken.None); } } Mesh = shape; }
public static Mesh Do(Mesh transformedKeep, Mesh transformedRemove, int opperation, IProgress <ProgressStatus> reporter, double amountPerOperation, double percentCompleted, ProgressStatus progressStatus, CancellationToken cancellationToken) { var libiglExe = "libigl_boolean.exe"; if (File.Exists(libiglExe) && IntPtr.Size == 8) // only try to run the improved booleans if we are 64 bit and it is there { string folderToSaveStlsTo = Path.Combine(ApplicationDataStorage.Instance.ApplicationTempDataPath, "amf_to_stl"); // Create directory if needed Directory.CreateDirectory(folderToSaveStlsTo); string stlFileA = Path.Combine(folderToSaveStlsTo, Path.ChangeExtension(Path.GetRandomFileName(), ".stl")); StlProcessing.Save(transformedKeep, stlFileA, CancellationToken.None); string stlFileB = Path.Combine(folderToSaveStlsTo, Path.ChangeExtension(Path.GetRandomFileName(), ".stl")); StlProcessing.Save(transformedRemove, stlFileB, CancellationToken.None); // wait for files to close Thread.Sleep(1000); string stlFileResult = Path.Combine(folderToSaveStlsTo, Path.ChangeExtension(Path.GetRandomFileName(), ".stl")); // if we have the libigl_boolean.exe var opperationString = "-"; switch (opperation) { case 0: opperationString = "+"; break; case 1: opperationString = "-"; break; case 2: opperationString = "&"; break; } var slicerProcess = new Process() { StartInfo = new ProcessStartInfo() { Arguments = "{0} {1} {2} {3}".FormatWith(stlFileA, stlFileB, stlFileResult, opperationString), CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, RedirectStandardError = true, RedirectStandardOutput = true, FileName = libiglExe, UseShellExecute = false } }; slicerProcess.Start(); slicerProcess.WaitForExit(); // wait for file to close Thread.Sleep(1000); // load up the var result = StlProcessing.Load(stlFileResult, CancellationToken.None); if (result != null) { return(result); } } switch (opperation) { case 0: return(PolygonMesh.Csg.CsgOperations.Union(transformedKeep, transformedRemove, (status, progress0To1) => { // Abort if flagged cancellationToken.ThrowIfCancellationRequested(); progressStatus.Status = status; progressStatus.Progress0To1 = percentCompleted + amountPerOperation * progress0To1; reporter.Report(progressStatus); }, cancellationToken)); case 1: return(PolygonMesh.Csg.CsgOperations.Subtract(transformedKeep, transformedRemove, (status, progress0To1) => { // Abort if flagged cancellationToken.ThrowIfCancellationRequested(); progressStatus.Status = status; progressStatus.Progress0To1 = percentCompleted + amountPerOperation * progress0To1; reporter?.Report(progressStatus); }, cancellationToken)); case 2: return(PolygonMesh.Csg.CsgOperations.Intersect(transformedKeep, transformedRemove, (status, progress0To1) => { // Abort if flagged cancellationToken.ThrowIfCancellationRequested(); progressStatus.Status = status; progressStatus.Progress0To1 = percentCompleted + amountPerOperation * progress0To1; reporter.Report(progressStatus); }, cancellationToken)); } return(null); }
public MoveInZControl(IInteractionVolumeContext context) : base(context) { theme = AppContext.Theme; Name = "MoveInZControl"; zHeightDisplayInfo = new InlineEditControl() { ForceHide = () => { var selectedItem = RootSelection; // if the selection changes if (selectedItem != ActiveSelectedItem) { return(true); } // if another control gets a hover if (InteractionContext.HoveredInteractionVolume != this && InteractionContext.HoveredInteractionVolume != null) { return(true); } // if we clicked on the control if (HadClickOnControl) { return(false); } return(false); } , GetDisplayString = (value) => "{0:0.0#}mm".FormatWith(value) }; zHeightDisplayInfo.VisibleChanged += (s, e) => { if (!zHeightDisplayInfo.Visible) { HadClickOnControl = false; } }; zHeightDisplayInfo.EditComplete += (s, e) => { var selectedItem = RootSelection; Matrix4X4 startingTransform = selectedItem.Matrix; var newZPosition = zHeightDisplayInfo.Value; if (InteractionContext.SnapGridDistance > 0) { // snap this position to the grid double snapGridDistance = InteractionContext.SnapGridDistance; // snap this position to the grid newZPosition = ((int)((newZPosition / snapGridDistance) + .5)) * snapGridDistance; } AxisAlignedBoundingBox originalSelectedBounds = selectedItem.GetAxisAlignedBoundingBox(); var moveAmount = newZPosition - originalSelectedBounds.MinXYZ.Z; if (moveAmount != 0) { selectedItem.Matrix = selectedItem.Matrix * Matrix4X4.CreateTranslation(0, 0, moveAmount); Invalidate(); } context.Scene.AddTransformSnapshot(startingTransform); }; InteractionContext.GuiSurface.AddChild(zHeightDisplayInfo); DrawOnTop = true; using (Stream arrowStream = AggContext.StaticData.OpenStream(Path.Combine("Stls", "up_pointer.stl"))) { upArrowMesh = StlProcessing.Load(arrowStream, CancellationToken.None); } CollisionVolume = upArrowMesh.CreateBVHData(); InteractionContext.GuiSurface.AfterDraw += InteractionLayer_AfterDraw; }
private static void CreateSlicedPartsThread() { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; while (!haltSlicingThread) { if (listOfSlicingItems.Count > 0) { PrintItemWrapper itemToSlice = listOfSlicingItems[0]; bool doMergeInSlicer = false; string mergeRules = ""; doMergeInSlicer = ActiveSliceSettings.Instance.ActiveSliceEngineType() == SlicingEngineTypes.MatterSlice; string[] stlFileLocations = GetStlFileLocations(itemToSlice.FileLocation, doMergeInSlicer, ref mergeRules); string fileToSlice = stlFileLocations[0]; // check that the STL file is currently on disk if (File.Exists(fileToSlice)) { itemToSlice.CurrentlySlicing = true; string currentConfigurationFileAndPath = Path.Combine(ApplicationDataStorage.Instance.GCodeOutputPath, "config_" + ActiveSliceSettings.Instance.GetLongHashCode().ToString() + ".ini"); ActiveSliceSettings.Instance.GenerateConfigFile(currentConfigurationFileAndPath, true); string gcodePathAndFileName = itemToSlice.GetGCodePathAndFileName(); bool gcodeFileIsComplete = itemToSlice.IsGCodeFileComplete(gcodePathAndFileName); if (!File.Exists(gcodePathAndFileName) || !gcodeFileIsComplete) { string commandArgs = ""; switch (ActiveSliceSettings.Instance.ActiveSliceEngineType()) { case SlicingEngineTypes.Slic3r: commandArgs = "--load \"" + currentConfigurationFileAndPath + "\" --output \"" + gcodePathAndFileName + "\" \"" + fileToSlice + "\""; break; case SlicingEngineTypes.CuraEngine: commandArgs = "-v -o \"" + gcodePathAndFileName + "\" " + EngineMappingCura.GetCuraCommandLineSettings() + " \"" + fileToSlice + "\""; break; case SlicingEngineTypes.MatterSlice: { EngineMappingsMatterSlice.WriteMatterSliceSettingsFile(currentConfigurationFileAndPath); if (mergeRules == "") { commandArgs = "-v -o \"" + gcodePathAndFileName + "\" -c \"" + currentConfigurationFileAndPath + "\""; } else { commandArgs = "-b {0} -v -o \"".FormatWith(mergeRules) + gcodePathAndFileName + "\" -c \"" + currentConfigurationFileAndPath + "\""; } foreach (string filename in stlFileLocations) { commandArgs = commandArgs + " \"" + filename + "\""; } } break; } #if false Mesh loadedMesh = StlProcessing.Load(fileToSlice); SliceLayers layers = new SliceLayers(); layers.GetPerimetersForAllLayers(loadedMesh, .2, .2); layers.DumpSegmentsToGcode("test.gcode"); #endif if (OsInformation.OperatingSystem == OSType.Android || ((OsInformation.OperatingSystem == OSType.Mac || runInProcess) && ActiveSliceSettings.Instance.ActiveSliceEngineType() == SlicingEngineTypes.MatterSlice)) { itemCurrentlySlicing = itemToSlice; MatterHackers.MatterSlice.LogOutput.GetLogWrites += SendProgressToItem; MatterSlice.MatterSlice.ProcessArgs(commandArgs); MatterHackers.MatterSlice.LogOutput.GetLogWrites -= SendProgressToItem; itemCurrentlySlicing = null; } else { slicerProcess = new Process(); slicerProcess.StartInfo.Arguments = commandArgs; string slicerFullPath = getSlicerFullPath(); slicerProcess.StartInfo.CreateNoWindow = true; slicerProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; slicerProcess.StartInfo.RedirectStandardError = true; slicerProcess.StartInfo.RedirectStandardOutput = true; slicerProcess.StartInfo.FileName = slicerFullPath; slicerProcess.StartInfo.UseShellExecute = false; slicerProcess.OutputDataReceived += (sender, args) => { if (args.Data != null) { string message = args.Data; message = message.Replace("=>", "").Trim(); if (message.Contains(".gcode")) { message = "Saving intermediate file"; } message += "..."; UiThread.RunOnIdle(() => { itemToSlice.OnSlicingOutputMessage(new StringEventArgs(message)); }); } }; slicerProcess.Start(); slicerProcess.BeginOutputReadLine(); string stdError = slicerProcess.StandardError.ReadToEnd(); slicerProcess.WaitForExit(); lock (slicerProcess) { slicerProcess = null; } } } try { if (File.Exists(gcodePathAndFileName) && File.Exists(currentConfigurationFileAndPath)) { // make sure we have not already written the settings onto this file bool fileHaseSettings = false; int bufferSize = 32000; using (Stream fileStream = File.OpenRead(gcodePathAndFileName)) { byte[] buffer = new byte[bufferSize]; fileStream.Seek(Math.Max(0, fileStream.Length - bufferSize), SeekOrigin.Begin); int numBytesRead = fileStream.Read(buffer, 0, bufferSize); string fileEnd = System.Text.Encoding.UTF8.GetString(buffer); if (fileEnd.Contains("GCode settings used")) { fileHaseSettings = true; } } if (!fileHaseSettings) { using (StreamWriter gcodeWirter = File.AppendText(gcodePathAndFileName)) { string oemName = "MatterControl"; if (OemSettings.Instance.WindowTitleExtra != null && OemSettings.Instance.WindowTitleExtra.Trim().Length > 0) { oemName = oemName + " - {0}".FormatWith(OemSettings.Instance.WindowTitleExtra); } gcodeWirter.WriteLine("; {0} Version {1} Build {2} : GCode settings used".FormatWith(oemName, VersionInfo.Instance.ReleaseVersion, VersionInfo.Instance.BuildVersion)); gcodeWirter.WriteLine("; Date {0} Time {1}:{2:00}".FormatWith(DateTime.Now.Date, DateTime.Now.Hour, DateTime.Now.Minute)); foreach (string line in File.ReadLines(currentConfigurationFileAndPath)) { gcodeWirter.WriteLine("; {0}".FormatWith(line)); } } } } } catch (Exception) { } } UiThread.RunOnIdle(() => { itemToSlice.CurrentlySlicing = false; itemToSlice.DoneSlicing = true; }); lock (listOfSlicingItems) { listOfSlicingItems.RemoveAt(0); } } Thread.Sleep(100); } }
public GuiWidget Create(IObject3D object3D, UndoBuffer undoBuffer, ThemeConfig theme) { this.item = object3D as OpenScadObject3D; var mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom) { HAnchor = HAnchor.Absolute, Width = 225 }; FlowLayoutWidget actionButtons = new FlowLayoutWidget(); mainContainer.AddChild(actionButtons); // TODO: This should use the same renaming and asset system as stl/amf assets string assetInfoPath = Path.ChangeExtension(item.ScriptPath, ".json"); bool isGenerator = File.Exists(assetInfoPath); if (isGenerator) { BuildGeneratorUI(theme, mainContainer, item.ScriptPath, assetInfoPath); } else { var editButton = new TextButton("Edit".Localize(), theme) { Margin = 5, ToolTipText = "Edit OpenSCAD script".Localize() }; editButton.Click += (s, e) => { Process.Start(item.ScriptPath); }; actionButtons.AddChild(editButton); var updateButton = new TextButton("Update".Localize(), theme) { Margin = 5, ToolTipText = "Compile model".Localize() }; if (!File.Exists(compilerPath)) { updateButton.Enabled = false; updateButton.ToolTipText = "OpenSCAD not installed".Localize(); } updateButton.Click += async(s, e) => { using (var meshStream = AggContext.StaticData.OpenStream(Path.Combine("Stls", "openscad_logo.stl"))) { this.item.Mesh = Object3D.Load(meshStream, ".stl", CancellationToken.None).Mesh; } // TODO: Use assets system string outputPath = Path.ChangeExtension(item.ScriptPath, ".stl"); int err = await Task.Run(() => ExecuteScript(item.ScriptPath, outputPath)); if (err == 0) { // Reload the mesh this.item.Mesh = StlProcessing.Load(outputPath, CancellationToken.None); } }; actionButtons.AddChild(updateButton); } return(mainContainer); }
public void SavingFunction() { currentlySaving = true; countThatHaveBeenSaved = 0; // first create images for all the parts foreach (string stlFileName in stlFilesToPrint) { Mesh loadedMesh = StlProcessing.Load(stlFileName); if (loadedMesh != null) { AxisAlignedBoundingBox aabb = loadedMesh.GetAxisAlignedBoundingBox(); RectangleDouble bounds2D = new RectangleDouble(aabb.minXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.x, aabb.maxXYZ.y); double widthInMM = bounds2D.Width + PartMarginMM * 2; double textSpaceMM = 5; double heightMM = textSpaceMM + bounds2D.Height + PartMarginMM * 2; string partName = System.IO.Path.GetFileName(System.IO.Path.GetFileName(stlFileName)); TypeFacePrinter typeFacePrinter = new TypeFacePrinter(partName, 28, Vector2.Zero, Justification.Center, Baseline.BoundsCenter); double sizeOfNameX = typeFacePrinter.GetSize().x + PartMarginPixels * 2; Vector2 sizeOfRender = new Vector2(widthInMM * PixelPerMM, heightMM * PixelPerMM); ImageBuffer imageOfPart = new ImageBuffer((int)(Math.Max(sizeOfNameX, sizeOfRender.x)), (int)(sizeOfRender.y), 32, new BlenderBGRA()); typeFacePrinter.Origin = new Vector2(imageOfPart.Width / 2, (textSpaceMM / 2) * PixelPerMM); Graphics2D partGraphics2D = imageOfPart.NewGraphics2D(); RectangleDouble rectBounds = new RectangleDouble(0, 0, imageOfPart.Width, imageOfPart.Height); double strokeWidth = .5 * PixelPerMM; rectBounds.Inflate(-strokeWidth / 2); RoundedRect rect = new RoundedRect(rectBounds, PartMarginMM * PixelPerMM); partGraphics2D.Render(rect, RGBA_Bytes.LightGray); Stroke rectOutline = new Stroke(rect, strokeWidth); partGraphics2D.Render(rectOutline, RGBA_Bytes.DarkGray); PolygonMesh.Rendering.OrthographicZProjection.DrawTo(partGraphics2D, loadedMesh, new Vector2(-bounds2D.Left + PartMarginMM, -bounds2D.Bottom + textSpaceMM + PartMarginMM), PixelPerMM, RGBA_Bytes.Black); partGraphics2D.Render(typeFacePrinter, RGBA_Bytes.Black); partImagesToPrint.Add(new PartImage(imageOfPart)); } countThatHaveBeenSaved++; if (UpdateRemainingItems != null) { UpdateRemainingItems(this, new StringEventArgs(Path.GetFileName(stlFileName))); } } partImagesToPrint.Sort(BiggestToLittlestImages); PdfDocument document = new PdfDocument(); document.Info.Title = "MatterHackers Parts Sheet"; document.Info.Author = "MatterHackers Inc."; document.Info.Subject = "This is a list of the parts that are in a queue from MatterControl."; document.Info.Keywords = "MatterControl, STL, 3D Printing"; int nextPartToPrintIndex = 0; int plateNumber = 1; bool done = false; while (!done && nextPartToPrintIndex < partImagesToPrint.Count) { PdfPage pdfPage = document.AddPage(); CreateOnePage(plateNumber++, ref nextPartToPrintIndex, pdfPage); } try { document.Save(pathAndFileToSaveTo); Process.Start(pathAndFileToSaveTo); } catch { } OnDoneSaving(); currentlySaving = false; }
static void CreateThumbnailsThread() { while (true) { if (listOfWidgetsNeedingThumbnails.Count > 0) { LibraryThumbnailWidget thumbnailWidget = listOfWidgetsNeedingThumbnails[0]; if (thumbnailWidget.printItem == null) { thumbnailWidget.image = new ImageBuffer(thumbnailWidget.noThumbnailImage); } else // generate the image { Mesh loadedMesh = StlProcessing.Load(thumbnailWidget.printItem.FileLocation); thumbnailWidget.image = new ImageBuffer(thumbnailWidget.buildingThumbnailImage); thumbnailWidget.Invalidate(); if (loadedMesh != null) { ImageBuffer tempImage = new ImageBuffer(thumbnailWidget.image.Width, thumbnailWidget.image.Height, 32, new BlenderBGRA()); Graphics2D partGraphics2D = tempImage.NewGraphics2D(); List <MeshEdge> nonManifoldEdges = loadedMesh.GetNonManifoldEdges(); if (nonManifoldEdges.Count > 0) { if (File.Exists("RunUnitTests.txt")) { partGraphics2D.Circle(4, 4, 4, RGBA_Bytes.Red); } } AxisAlignedBoundingBox aabb = loadedMesh.GetAxisAlignedBoundingBox(); double maxSize = Math.Max(aabb.XSize, aabb.YSize); double scale = thumbnailWidget.image.Width / (maxSize * 1.2); RectangleDouble bounds2D = new RectangleDouble(aabb.minXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.x, aabb.maxXYZ.y); PolygonMesh.Rendering.OrthographicZProjection.DrawTo(partGraphics2D, loadedMesh, new Vector2((thumbnailWidget.image.Width / scale - bounds2D.Width) / 2 - bounds2D.Left, (thumbnailWidget.image.Height / scale - bounds2D.Height) / 2 - bounds2D.Bottom), scale, thumbnailWidget.FillColor); thumbnailWidget.image = new ImageBuffer(tempImage); } else { thumbnailWidget.image = new ImageBuffer(thumbnailWidget.noThumbnailImage); } } thumbnailWidget.Invalidate(); using (TimedLock.Lock(listOfWidgetsNeedingThumbnails, "CreateThumbnailsThread()")) { listOfWidgetsNeedingThumbnails.RemoveAt(0); foreach (LibraryThumbnailWidget part in listOfWidgetsNeedingThumbnails) { // mark them so we try to add them again if needed part.thumbNailHasBeenRequested = false; } listOfWidgetsNeedingThumbnails.Clear(); } } Thread.Sleep(100); } }
void createThumbnailWorker_DoWork(object sender, DoWorkEventArgs e) { PartThumbnailWidget thumbnailWidget = e.Argument as PartThumbnailWidget; if (thumbnailWidget != null) { if (thumbnailWidget.printItem == null) { thumbnailWidget.tumbnailImage = new ImageBuffer(thumbnailWidget.noThumbnailImage); thumbnailWidget.Invalidate(); return; } string stlHashCode = thumbnailWidget.PrintItem.StlFileHashCode.ToString(); Point2D bigRenderSize = new Point2D(460, 460); ImageBuffer bigRender = LoadImageFromDisk(thumbnailWidget, stlHashCode, bigRenderSize); if (bigRender == null) { Mesh loadedMesh = StlProcessing.Load(thumbnailWidget.PrintItem.FileLocation); thumbnailWidget.tumbnailImage = new ImageBuffer(thumbnailWidget.buildingThumbnailImage); thumbnailWidget.tumbnailImage.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); bigRender = BuildImageFromSTL(loadedMesh, stlHashCode, bigRenderSize); if (bigRender == null) { bigRender = new ImageBuffer(thumbnailWidget.noThumbnailImage); } } switch (thumbnailWidget.Size) { case ImageSizes.Size50x50: { ImageBuffer halfWay1 = new ImageBuffer(200, 200, 32, new BlenderBGRA()); halfWay1.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); halfWay1.NewGraphics2D().Render(bigRender, 0, 0, 0, (double)halfWay1.Width / bigRender.Width, (double)halfWay1.Height / bigRender.Height); ImageBuffer halfWay2 = new ImageBuffer(100, 100, 32, new BlenderBGRA()); halfWay2.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); halfWay2.NewGraphics2D().Render(halfWay1, 0, 0, 0, (double)halfWay2.Width / halfWay1.Width, (double)halfWay2.Height / halfWay1.Height); thumbnailWidget.tumbnailImage = new ImageBuffer(50, 50, 32, new BlenderBGRA()); thumbnailWidget.tumbnailImage.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); thumbnailWidget.tumbnailImage.NewGraphics2D().Render(halfWay2, 0, 0, 0, (double)thumbnailWidget.tumbnailImage.Width / halfWay2.Width, (double)thumbnailWidget.tumbnailImage.Height / halfWay2.Height); } break; case ImageSizes.Size115x115: { ImageBuffer halfWay1 = new ImageBuffer(230, 230, 32, new BlenderBGRA()); halfWay1.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); halfWay1.NewGraphics2D().Render(bigRender, 0, 0, 0, (double)halfWay1.Width / bigRender.Width, (double)halfWay1.Height / bigRender.Height); thumbnailWidget.tumbnailImage = new ImageBuffer(115, 115, 32, new BlenderBGRA()); thumbnailWidget.tumbnailImage.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); thumbnailWidget.tumbnailImage.NewGraphics2D().Render(halfWay1, 0, 0, 0, (double)thumbnailWidget.tumbnailImage.Width / halfWay1.Width, (double)thumbnailWidget.tumbnailImage.Height / halfWay1.Height); } break; default: throw new NotImplementedException(); } UiThread.RunOnIdle(thumbnailWidget.EnsureImageUpdated); } }