/* * GNU AFFERO GENERAL PUBLIC LICENSE * Version 3, 19 November 2007 * Copyright (C) 2007 Free Software Foundation, Inc. * Everyone is permitted to copy and distribute verbatim copies * of this license document, but changing it is not allowed. */ using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Numerics; using UVtools.Core.Extensions; using UVtools.Core.FileFormats; namespace UVtools.Core.MeshFormats; public class AMFMeshFile : MeshFile { #region Members private readonly Dictionary _vertexCache = new(VertexCacheSize); private FileStream _triangleStream = null!; #endregion #region Properties public static FileExtension FileExtension => new(typeof(AMFMeshFile), "amf", "Additive Manufacturing Format"); #endregion #region Constructor public AMFMeshFile(string filePath, FileMode fileMode, MeshFileFormat fileFormat = MeshFileFormat.ASCII, FileFormat? slicerFile = null) : base(filePath, fileMode, MeshFileFormat.ASCII, slicerFile) { } #endregion #region Methods public override void BeginWrite() { /* Create a stream to store the triangles (faces) as they come through */ _triangleStream = new FileStream(PathExtensions.GetTemporaryFilePathWithExtension("trig", $"{About.Software}_"), FileMode.Create, FileAccess.ReadWrite, FileShare.None, 81920, FileOptions.DeleteOnClose); MeshStream.WriteLineLF(""); MeshStream.WriteLineLF(""); MeshStream.WriteLineLF($"\t{FilenameWithoutExtension}"); MeshStream.WriteLineLF($"\t{HeaderComment}"); MeshStream.WriteLineLF("\t"); MeshStream.WriteLineLF("\t\t"); MeshStream.WriteLineLF("\t\t\t"); } public override void WriteTriangle(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 normal) { if (!_vertexCache.ContainsKey(p1)) { MeshStream.WriteLineLF($"\t\t\t\t"); MeshStream.WriteLineLF($"\t\t\t\t\t"); MeshStream.WriteLineLF($"\t\t\t\t\t\t{p1.X:F6}"); MeshStream.WriteLineLF($"\t\t\t\t\t\t{p1.Y:F6}"); MeshStream.WriteLineLF($"\t\t\t\t\t\t{p1.Z:F6}"); MeshStream.WriteLineLF($"\t\t\t\t\t"); MeshStream.WriteLineLF($"\t\t\t\t"); _vertexCache.Add(p1, VertexCount); VertexCount++; } if (!_vertexCache.ContainsKey(p2)) { MeshStream.WriteLineLF($"\t\t\t\t"); MeshStream.WriteLineLF($"\t\t\t\t\t"); MeshStream.WriteLineLF($"\t\t\t\t\t\t{p2.X:F6}"); MeshStream.WriteLineLF($"\t\t\t\t\t\t{p2.Y:F6}"); MeshStream.WriteLineLF($"\t\t\t\t\t\t{p2.Z:F6}"); MeshStream.WriteLineLF($"\t\t\t\t\t"); MeshStream.WriteLineLF($"\t\t\t\t"); _vertexCache.Add(p2, VertexCount); VertexCount++; } if (!_vertexCache.ContainsKey(p3)) { MeshStream.WriteLineLF($"\t\t\t\t"); MeshStream.WriteLineLF($"\t\t\t\t\t"); MeshStream.WriteLineLF($"\t\t\t\t\t\t{p3.X:F6}"); MeshStream.WriteLineLF($"\t\t\t\t\t\t{p3.Y:F6}"); MeshStream.WriteLineLF($"\t\t\t\t\t\t{p3.Z:F6}"); MeshStream.WriteLineLF($"\t\t\t\t\t"); MeshStream.WriteLineLF($"\t\t\t\t"); _vertexCache.Add(p3, VertexCount); VertexCount++; } _triangleStream.WriteLineLF($"\t\t\t\t"); _triangleStream.WriteLineLF($"\t\t\t\t\t{_vertexCache[p1]}"); _triangleStream.WriteLineLF($"\t\t\t\t\t{_vertexCache[p2]}"); _triangleStream.WriteLineLF($"\t\t\t\t\t{_vertexCache[p3]}"); _triangleStream.WriteLineLF($"\t\t\t\t"); TriangleCount++; /* If we are getting close to the cache size. we do *not* want to go over the capacity as that will trigger * an allocation of a bigger buffer and copy of the kvp's */ if (_vertexCache.Count >= VertexCacheSize - 10) { _vertexCache.Clear(); } } public override void EndWrite() { _vertexCache.Clear(); MeshStream.WriteLineLF("\t\t\t"); MeshStream.WriteLineLF("\t\t\t"); MeshStream.WriteLineLF("\t\t\t\tModel"); _triangleStream.Seek(0, SeekOrigin.Begin); _triangleStream.CopyTo(MeshStream); _triangleStream.Dispose(); MeshStream.WriteLineLF("\t\t\t"); MeshStream.WriteLineLF("\t\t"); MeshStream.WriteLineLF("\t"); MeshStream.WriteLineLF(""); var tmpFile = PathExtensions.GetTemporaryFilePathWithExtension("tmp", $"{About.Software}_"); if (File.Exists(tmpFile)) File.Delete(tmpFile); using (var zip = ZipFile.Open(tmpFile, ZipArchiveMode.Create)) { MeshStream.Seek(0, SeekOrigin.Begin); zip.PutFileContent(Filename, MeshStream, ZipArchiveMode.Create); } MeshStream.Dispose(); File.Move(tmpFile, FilePath, true); } #endregion }