610 lines
No EOL
15 KiB
C#
610 lines
No EOL
15 KiB
C#
/*
|
|
* MIT License
|
|
*
|
|
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
/**
|
|
* by bn on 30/06/2018.
|
|
*/
|
|
|
|
namespace Photon.Parts
|
|
{
|
|
public class PhotonFile
|
|
{
|
|
private IFileHeader iFileHeader;
|
|
private int islandLayerCount;
|
|
private List<int> islandLayers;
|
|
private StringBuilder islandList;
|
|
private List<PhotonFileLayer> layers;
|
|
private int margin;
|
|
private List<int> marginLayers;
|
|
private PhotonFilePreview previewOne;
|
|
private PhotonFilePreview previewTwo;
|
|
|
|
public void AdjustLayerSettings()
|
|
{
|
|
for (int i = 0; i < layers.Count; i++)
|
|
{
|
|
PhotonFileLayer layer = layers[i];
|
|
if (i < iFileHeader.GetBottomLayers())
|
|
{
|
|
layer.SetLayerExposure(iFileHeader.GetBottomExposureTimeSeconds());
|
|
}
|
|
else
|
|
{
|
|
layer.SetLayerExposure(iFileHeader.GetNormalExposure());
|
|
}
|
|
layer.SetLayerOffTimeSeconds(iFileHeader.GetOffTimeSeconds());
|
|
}
|
|
}
|
|
|
|
public void Calculate(Action<string> reportProgress)
|
|
{
|
|
PhotonFileLayer.CalculateLayers((PhotonFileHeader)iFileHeader, layers, margin, reportProgress);
|
|
ResetMarginAndIslandInfo();
|
|
}
|
|
|
|
public void Calculate(int layerNo)
|
|
{
|
|
PhotonFileLayer.CalculateLayers((PhotonFileHeader)iFileHeader, layers, margin, layerNo);
|
|
ResetMarginAndIslandInfo();
|
|
}
|
|
|
|
public void CalculateAaLayers(Action<string> reportProgress, PhotonAaMatrix photonAaMatrix)
|
|
{
|
|
PhotonFileLayer.CalculateAALayers((PhotonFileHeader)iFileHeader, layers, photonAaMatrix, reportProgress);
|
|
}
|
|
|
|
public void ChangeToVersion2()
|
|
{
|
|
iFileHeader.SetFileVersion(2);
|
|
}
|
|
|
|
public void FixAll(Action<string> reportProgress)
|
|
{
|
|
bool layerWasFixed;
|
|
do
|
|
{
|
|
do
|
|
{
|
|
// Repeatedly fix layers until none are possible to fix
|
|
// Fixing some layers can make other layers auto-fixable
|
|
layerWasFixed = FixLayers(reportProgress);
|
|
} while (layerWasFixed);
|
|
if (islandLayers.Count > 0)
|
|
{
|
|
// Nothing can be done further, just remove all layers left
|
|
layerWasFixed = RemoveAllIslands(reportProgress) || layerWasFixed;
|
|
}
|
|
if (layerWasFixed && islandLayers.Count > 0)
|
|
{
|
|
// We could've created new islands by removing islands, repeat fixing process
|
|
// until everything is fixed or nothing can be done
|
|
reportProgress?.Invoke("<br>Some layers were fixed, but " + islandLayers.Count + " still unsupported, repeating...<br>");
|
|
}
|
|
} while (layerWasFixed);
|
|
}
|
|
|
|
public void FixLayerHeights()
|
|
{
|
|
int index = 0;
|
|
foreach (var layer in layers)
|
|
{
|
|
layer.SetLayerPositionZ(index * iFileHeader.GetLayerHeight());
|
|
index++;
|
|
}
|
|
}
|
|
|
|
public bool FixLayers(Action<string> reportProgress)
|
|
{
|
|
bool layersFixed = false;
|
|
PhotonLayer layer = null;
|
|
foreach (int layerNo in islandLayers)
|
|
{
|
|
reportProgress?.Invoke("Checking layer " + layerNo);
|
|
|
|
// Unpack the layer data to the layer utility class
|
|
PhotonFileLayer fileLayer = layers[layerNo];
|
|
if (layer == null)
|
|
{
|
|
layer = fileLayer.GetLayer();
|
|
}
|
|
else
|
|
{
|
|
fileLayer.GetUpdateLayer(layer);
|
|
}
|
|
|
|
int changed = Fixit(reportProgress, layer, fileLayer, 10);
|
|
if (changed == 0)
|
|
{
|
|
reportProgress?.Invoke(", but nothing could be done.");
|
|
}
|
|
else
|
|
{
|
|
fileLayer.SaveLayer(layer);
|
|
Calculate(layerNo);
|
|
if (layerNo < GetLayerCount() - 1)
|
|
{
|
|
Calculate(layerNo + 1);
|
|
}
|
|
layersFixed = true;
|
|
}
|
|
|
|
reportProgress?.Invoke("<br>");
|
|
}
|
|
FindIslands();
|
|
return layersFixed;
|
|
}
|
|
|
|
public int GetAALevels()
|
|
{
|
|
return iFileHeader.GetAALevels();
|
|
}
|
|
|
|
public int GetHeight()
|
|
{
|
|
return iFileHeader.GetResolutionX();
|
|
}
|
|
|
|
public string GetInformation()
|
|
{
|
|
if (iFileHeader == null) return "";
|
|
return iFileHeader.GetInformation();
|
|
}
|
|
|
|
public int GetIslandLayerCount()
|
|
{
|
|
if (islandList == null)
|
|
{
|
|
FindIslands();
|
|
}
|
|
return islandLayerCount;
|
|
}
|
|
|
|
public List<int> GetIslandLayers()
|
|
{
|
|
if (islandList == null)
|
|
{
|
|
FindIslands();
|
|
}
|
|
return islandLayers;
|
|
}
|
|
|
|
public PhotonFileLayer GetLayer(int i)
|
|
{
|
|
if (layers != null && layers.Count > i)
|
|
{
|
|
return layers[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public int GetLayerCount()
|
|
{
|
|
return iFileHeader.GetNumberOfLayers();
|
|
}
|
|
|
|
public string GetLayerInformation()
|
|
{
|
|
if (islandList == null)
|
|
{
|
|
FindIslands();
|
|
}
|
|
if (islandLayerCount == 0)
|
|
{
|
|
return "Whoopee, all is good, no unsupported areas";
|
|
}
|
|
else if (islandLayerCount == 1)
|
|
{
|
|
return "Unsupported islands found in layer " + islandList.ToString();
|
|
}
|
|
return "Unsupported islands found in layers " + islandList.ToString();
|
|
}
|
|
|
|
public string GetMarginInformation()
|
|
{
|
|
if (marginLayers == null)
|
|
{
|
|
return "No safety margin set, printing to the border.";
|
|
}
|
|
else
|
|
{
|
|
if (marginLayers.Count == 0)
|
|
{
|
|
return "The model is within the defined safety margin (" + this.margin + " pixels).";
|
|
}
|
|
else if (marginLayers.Count == 1)
|
|
{
|
|
return "The layer " + marginLayers[0] + " contains model parts that extend beyond the margin.";
|
|
}
|
|
var marginList = new StringBuilder();
|
|
int count = 0;
|
|
foreach (var layer in marginLayers)
|
|
{
|
|
if (count > 10)
|
|
{
|
|
marginList.Append(", ...");
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (marginList.Length > 0) marginList.Append(", ");
|
|
marginList.Append(layer);
|
|
}
|
|
count++;
|
|
}
|
|
return "The layers " + marginList.ToString() + " contains model parts that extend beyond the margin.";
|
|
}
|
|
}
|
|
|
|
public List<int> GetMarginLayers()
|
|
{
|
|
if (marginLayers == null)
|
|
{
|
|
return new List<int>();
|
|
}
|
|
return marginLayers;
|
|
}
|
|
|
|
public IFileHeader GetPhotonFileHeader()
|
|
{
|
|
return iFileHeader;
|
|
}
|
|
|
|
public long GetPixels()
|
|
{
|
|
long total = 0;
|
|
if (layers != null)
|
|
{
|
|
foreach (var layer in layers)
|
|
{
|
|
total += layer.GetPixels();
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
|
|
public PhotonFilePreview GetPreviewOne()
|
|
{
|
|
return previewOne;
|
|
}
|
|
|
|
public PhotonFilePreview GetPreviewTwo()
|
|
{
|
|
return previewTwo;
|
|
}
|
|
|
|
public int GetVersion()
|
|
{
|
|
return iFileHeader.GetVersion();
|
|
}
|
|
|
|
public int GetWidth()
|
|
{
|
|
return iFileHeader.GetResolutionY();
|
|
}
|
|
|
|
public float GetZdrift()
|
|
{
|
|
float expectedHeight = iFileHeader.GetLayerHeight() * (iFileHeader.GetNumberOfLayers() - 1);
|
|
float actualHeight = layers[layers.Count - 1].GetLayerPositionZ();
|
|
return expectedHeight - actualHeight;
|
|
}
|
|
|
|
public bool HasAA()
|
|
{
|
|
return iFileHeader.HasAA();
|
|
}
|
|
|
|
public PhotonFile ReadFile(string fileName, Action<string> reportProgress)
|
|
{
|
|
using (var file = File.OpenRead(fileName))
|
|
{
|
|
return ReadFile(GetBinaryData(file), reportProgress);
|
|
}
|
|
}
|
|
|
|
public bool RemoveAllIslands(Action<string> reportProgress)
|
|
{
|
|
bool layersFixed = false;
|
|
reportProgress?.Invoke("Removing islands from " + islandLayers.Count + " layers...<br>");
|
|
PhotonLayer layer = null;
|
|
foreach (var layerNo in islandLayers)
|
|
{
|
|
PhotonFileLayer fileLayer = layers[layerNo];
|
|
if (layer == null)
|
|
{
|
|
layer = fileLayer.GetLayer();
|
|
}
|
|
else
|
|
{
|
|
fileLayer.GetUpdateLayer(layer);
|
|
}
|
|
reportProgress?.Invoke("Removing islands from layer " + layerNo);
|
|
|
|
int removed = layer.RemoveIslands();
|
|
if (removed == 0)
|
|
{
|
|
reportProgress?.Invoke(", but nothing could be done.");
|
|
}
|
|
else
|
|
{
|
|
reportProgress?.Invoke(", " + removed + " islands removed");
|
|
fileLayer.SaveLayer(layer);
|
|
Calculate(layerNo);
|
|
if (layerNo < GetLayerCount() - 1)
|
|
{
|
|
Calculate(layerNo + 1);
|
|
}
|
|
layersFixed = true;
|
|
}
|
|
reportProgress?.Invoke("<br>");
|
|
}
|
|
FindIslands();
|
|
return layersFixed;
|
|
}
|
|
|
|
public void SaveFile(string fileName)
|
|
{
|
|
using (var fileOutputStream = new BinaryWriter(File.OpenWrite(fileName)))
|
|
{
|
|
WriteFile(fileOutputStream);
|
|
}
|
|
}
|
|
|
|
// only call this when recalculating AA levels
|
|
public void SetAALevels(int levels)
|
|
{
|
|
iFileHeader.SetAALevels(levels, layers);
|
|
}
|
|
|
|
public void SetMargin(int margin)
|
|
{
|
|
this.margin = margin;
|
|
}
|
|
|
|
public void UnLink()
|
|
{
|
|
while (layers.Count > 0)
|
|
{
|
|
PhotonFileLayer layer = layers[0];
|
|
layers.RemoveAt(0);
|
|
layer.UnLink();
|
|
}
|
|
if (islandLayers != null)
|
|
{
|
|
islandLayers.Clear();
|
|
}
|
|
if (marginLayers != null)
|
|
{
|
|
marginLayers.Clear();
|
|
}
|
|
iFileHeader.UnLink();
|
|
iFileHeader = null;
|
|
previewOne.UnLink();
|
|
previewOne = null;
|
|
previewTwo.UnLink();
|
|
previewTwo = null;
|
|
}
|
|
|
|
private void FindIslands()
|
|
{
|
|
if (islandLayers != null)
|
|
{
|
|
islandLayers.Clear();
|
|
islandList = new StringBuilder();
|
|
islandLayerCount = 0;
|
|
if (layers != null)
|
|
{
|
|
for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++)
|
|
{
|
|
PhotonFileLayer layer = layers[i];
|
|
if (layer.GetIsLandsCount() > 0)
|
|
{
|
|
if (islandLayerCount < 11)
|
|
{
|
|
if (islandLayerCount == 10)
|
|
{
|
|
islandList.Append(", ...");
|
|
}
|
|
else
|
|
{
|
|
if (islandList.Length > 0) islandList.Append(", ");
|
|
islandList.Append(i);
|
|
}
|
|
}
|
|
islandLayerCount++;
|
|
islandLayers.Add(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private int Fixit(Action<string> reportProgress, PhotonLayer layer, PhotonFileLayer fileLayer, int loops)
|
|
{
|
|
int changed = layer.Fixlayer();
|
|
if (changed > 0)
|
|
{
|
|
layer.Reduce();
|
|
fileLayer.UpdateLayerIslands(layer);
|
|
reportProgress?.Invoke(", " + changed + " pixels changed");
|
|
if (loops > 0)
|
|
{
|
|
changed += Fixit(reportProgress, layer, fileLayer, loops - 1);
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
private byte[] GetBinaryData(FileStream entry)
|
|
{
|
|
int fileSize = (int)entry.Length;
|
|
byte[] fileData = new byte[fileSize];
|
|
|
|
var stream = new BinaryReader(entry);
|
|
int bytesRead = 0;
|
|
while (bytesRead < fileSize)
|
|
{
|
|
int readCount = stream.Read(fileData, bytesRead, fileSize - bytesRead);
|
|
if (readCount < 0)
|
|
{
|
|
throw new IOException("Could not read all bytes of the file");
|
|
}
|
|
bytesRead += readCount;
|
|
}
|
|
|
|
return fileData;
|
|
}
|
|
|
|
private PhotonFile ReadFile(byte[] file, Action<string> reportProgress)
|
|
{
|
|
reportProgress?.Invoke("Reading Photon file header information...");
|
|
var photonFileHeader = new PhotonFileHeader(file);
|
|
iFileHeader = photonFileHeader;
|
|
|
|
reportProgress?.Invoke("Reading photon large preview image information...");
|
|
previewOne = new PhotonFilePreview(photonFileHeader.GetPreviewOneOffsetAddress(), file);
|
|
reportProgress?.Invoke("Reading photon small preview image information...");
|
|
previewTwo = new PhotonFilePreview(photonFileHeader.GetPreviewTwoOffsetAddress(), file);
|
|
if (photonFileHeader.GetVersion() > 1)
|
|
{
|
|
reportProgress?.Invoke("Reading Print parameters information...");
|
|
photonFileHeader.ReadParameters(file);
|
|
}
|
|
reportProgress?.Invoke("Reading photon layers information...");
|
|
layers = PhotonFileLayer.ReadLayers(photonFileHeader, file, margin, reportProgress);
|
|
ResetMarginAndIslandInfo();
|
|
|
|
return this;
|
|
}
|
|
|
|
private void ResetMarginAndIslandInfo()
|
|
{
|
|
islandList = null;
|
|
islandLayerCount = 0;
|
|
islandLayers = new List<int>();
|
|
|
|
if (margin > 0)
|
|
{
|
|
marginLayers = new List<int>();
|
|
int i = 0;
|
|
foreach (PhotonFileLayer layer in layers)
|
|
{
|
|
if (layer.DoExtendMargin())
|
|
{
|
|
marginLayers.Add(i);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void WriteFile(BinaryWriter writer)
|
|
{
|
|
int antiAliasLevel = iFileHeader.GetAALevels();
|
|
|
|
int headerPos = 0;
|
|
int previewOnePos = headerPos + iFileHeader.GetByteSize();
|
|
int previewTwoPos = previewOnePos + previewOne.GetByteSize();
|
|
int layerDefinitionPos = previewTwoPos + previewTwo.GetByteSize();
|
|
|
|
int parametersPos = 0;
|
|
int machineInfoPos = 0;
|
|
if (iFileHeader.GetVersion() > 1)
|
|
{
|
|
parametersPos = layerDefinitionPos;
|
|
if (((PhotonFileHeader)iFileHeader).photonFileMachineInfo.GetByteSize() > 0)
|
|
{
|
|
machineInfoPos = parametersPos + ((PhotonFileHeader)iFileHeader).photonFilePrintParameters.GetByteSize();
|
|
layerDefinitionPos = machineInfoPos + ((PhotonFileHeader)iFileHeader).photonFileMachineInfo.GetByteSize();
|
|
}
|
|
else
|
|
{
|
|
layerDefinitionPos = parametersPos + ((PhotonFileHeader)iFileHeader).photonFilePrintParameters.GetByteSize();
|
|
}
|
|
}
|
|
|
|
int dataPosition = layerDefinitionPos + (PhotonFileLayer.GetByteSize() * iFileHeader.GetNumberOfLayers() * antiAliasLevel);
|
|
|
|
((PhotonFileHeader)iFileHeader).Save(writer, previewOnePos, previewTwoPos, layerDefinitionPos, parametersPos, machineInfoPos);
|
|
previewOne.Save(writer, previewOnePos);
|
|
previewTwo.Save(writer, previewTwoPos);
|
|
|
|
if (iFileHeader.GetVersion() > 1)
|
|
{
|
|
((PhotonFileHeader)iFileHeader).photonFilePrintParameters.Save(writer);
|
|
((PhotonFileHeader)iFileHeader).photonFileMachineInfo.Save(writer, machineInfoPos);
|
|
}
|
|
|
|
// Optimize order for speed read on photon
|
|
for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++)
|
|
{
|
|
PhotonFileLayer layer = layers[i];
|
|
dataPosition = layer.SavePos(dataPosition);
|
|
if (antiAliasLevel > 1)
|
|
{
|
|
for (int a = 0; a < (antiAliasLevel - 1); a++)
|
|
{
|
|
dataPosition = layer.GetAntiAlias(a).SavePos(dataPosition);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Order for backward compatibility with photon/cbddlp version 1
|
|
for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++)
|
|
{
|
|
layers[i].Save(writer);
|
|
}
|
|
|
|
if (antiAliasLevel > 1)
|
|
{
|
|
for (int a = 0; a < (antiAliasLevel - 1); a++)
|
|
{
|
|
for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++)
|
|
{
|
|
layers[i].GetAntiAlias(a).Save(writer);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Optimize order for speed read on photon
|
|
for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++)
|
|
{
|
|
PhotonFileLayer layer = layers[i];
|
|
layer.SaveData(writer);
|
|
if (antiAliasLevel > 1)
|
|
{
|
|
for (int a = 0; a < (antiAliasLevel - 1); a++)
|
|
{
|
|
layer.GetAntiAlias(a).SaveData(writer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |