Migrate GCodeVisualizer and MeshViewer content into MatterControl
This commit is contained in:
parent
6edbbffabc
commit
7a27433bf0
25 changed files with 4452 additions and 28 deletions
71
MatterControl.OpenGL/GCodeRenderer/ColorVertexData.cs
Normal file
71
MatterControl.OpenGL/GCodeRenderer/ColorVertexData.cs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
using MatterHackers.Agg;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ColorVertexData
|
||||
{
|
||||
public byte r;
|
||||
public byte g;
|
||||
public byte b;
|
||||
public byte a;
|
||||
|
||||
public float normalX;
|
||||
public float normalY;
|
||||
public float normalZ;
|
||||
|
||||
public float positionX;
|
||||
public float positionY;
|
||||
public float positionZ;
|
||||
|
||||
public static readonly int Stride = Marshal.SizeOf(default(ColorVertexData));
|
||||
|
||||
public ColorVertexData(Vector3 position, Vector3 normal, RGBA_Bytes color)
|
||||
{
|
||||
r = (byte)color.Red0To255;
|
||||
g = (byte)color.Green0To255;
|
||||
b = (byte)color.Blue0To255;
|
||||
a = (byte)color.Alpha0To255;
|
||||
|
||||
normalX = (float)normal.x;
|
||||
normalY = (float)normal.y;
|
||||
normalZ = (float)normal.z;
|
||||
|
||||
positionX = (float)position.x;
|
||||
positionY = (float)position.y;
|
||||
positionZ = (float)position.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
MatterControl.OpenGL/GCodeRenderer/ExtrusionColors.cs
Normal file
76
MatterControl.OpenGL/GCodeRenderer/ExtrusionColors.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
using MatterHackers.Agg;
|
||||
|
||||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public class ExtrusionColors
|
||||
{
|
||||
private SortedList<float, RGBA_Bytes> speedColorLookup = new SortedList<float, RGBA_Bytes>();
|
||||
|
||||
public RGBA_Bytes GetColorForSpeed(float speed)
|
||||
{
|
||||
if (speed > 0)
|
||||
{
|
||||
lock(speedColorLookup)
|
||||
{
|
||||
double startColor = 223.0 / 360.0;
|
||||
double endColor = 5.0 / 360.0;
|
||||
double delta = startColor - endColor;
|
||||
|
||||
if (!speedColorLookup.ContainsKey(speed))
|
||||
{
|
||||
RGBA_Bytes color = RGBA_Floats.FromHSL(startColor, .99, .49).GetAsRGBA_Bytes();
|
||||
speedColorLookup.Add(speed, color);
|
||||
|
||||
if (speedColorLookup.Count > 1)
|
||||
{
|
||||
double step = delta / (speedColorLookup.Count - 1);
|
||||
for (int index = 0; index < speedColorLookup.Count; index++)
|
||||
{
|
||||
double offset = step * index;
|
||||
double fixedColor = startColor - offset;
|
||||
KeyValuePair<float, RGBA_Bytes> keyValue = speedColorLookup.ElementAt(index);
|
||||
speedColorLookup[keyValue.Key] = RGBA_Floats.FromHSL(fixedColor, .99, .49).GetAsRGBA_Bytes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return speedColorLookup[speed];
|
||||
}
|
||||
}
|
||||
|
||||
return RGBA_Bytes.Black;
|
||||
}
|
||||
}
|
||||
}
|
||||
103
MatterControl.OpenGL/GCodeRenderer/GCodeRenderInfo.cs
Normal file
103
MatterControl.OpenGL/GCodeRenderer/GCodeRenderInfo.cs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Transform;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public class GCodeRenderInfo
|
||||
{
|
||||
private Vector2[] extruderOffsets;
|
||||
|
||||
public Vector2 GetExtruderOffset(int index)
|
||||
{
|
||||
if (extruderOffsets != null
|
||||
&& extruderOffsets.Length > index)
|
||||
{
|
||||
return extruderOffsets[index];
|
||||
}
|
||||
|
||||
return Vector2.Zero;
|
||||
}
|
||||
|
||||
public Func<int, RGBA_Bytes> GetMaterialColor { get; }
|
||||
|
||||
public int startLayerIndex;
|
||||
|
||||
public int StartLayerIndex { get { return startLayerIndex; } }
|
||||
|
||||
private int endLayerIndex;
|
||||
|
||||
public int EndLayerIndex { get { return endLayerIndex; } }
|
||||
|
||||
private Affine transform;
|
||||
|
||||
public Affine Transform { get { return transform; } }
|
||||
|
||||
private double layerScale;
|
||||
|
||||
public double LayerScale { get { return layerScale; } }
|
||||
|
||||
private RenderType currentRenderType;
|
||||
|
||||
public RenderType CurrentRenderType { get { return currentRenderType; } }
|
||||
|
||||
private double featureToStartOnRatio0To1;
|
||||
|
||||
public double FeatureToStartOnRatio0To1 { get { return featureToStartOnRatio0To1; } }
|
||||
|
||||
private double featureToEndOnRatio0To1;
|
||||
|
||||
public double FeatureToEndOnRatio0To1 { get { return featureToEndOnRatio0To1; } }
|
||||
|
||||
public GCodeRenderInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public GCodeRenderInfo(int startLayerIndex, int endLayerIndex,
|
||||
Affine transform, double layerScale, RenderType renderType,
|
||||
double featureToStartOnRatio0To1, double featureToEndOnRatio0To1,
|
||||
Vector2[] extruderOffsets,
|
||||
Func<int, RGBA_Bytes> getMaterialColor)
|
||||
{
|
||||
this.GetMaterialColor = getMaterialColor;
|
||||
this.startLayerIndex = startLayerIndex;
|
||||
this.endLayerIndex = endLayerIndex;
|
||||
this.transform = transform;
|
||||
this.layerScale = layerScale;
|
||||
this.currentRenderType = renderType;
|
||||
this.featureToStartOnRatio0To1 = featureToStartOnRatio0To1;
|
||||
this.featureToEndOnRatio0To1 = featureToEndOnRatio0To1;
|
||||
this.extruderOffsets = extruderOffsets;
|
||||
}
|
||||
}
|
||||
}
|
||||
406
MatterControl.OpenGL/GCodeRenderer/GCodeRenderer.cs
Normal file
406
MatterControl.OpenGL/GCodeRenderer/GCodeRenderer.cs
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
Copyright (c) 2017, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.RenderOpenGl.OpenGl;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
[Flags]
|
||||
public enum RenderType
|
||||
{
|
||||
None = 0,
|
||||
Extrusions = 1,
|
||||
Moves = 2,
|
||||
Retractions = 4,
|
||||
SpeedColors = 8,
|
||||
SimulateExtrusion = 16,
|
||||
HideExtruderOffsets = 32,
|
||||
TransparentExtrusion = 64,
|
||||
};
|
||||
|
||||
public class GCodeRenderer : IDisposable
|
||||
{
|
||||
public static double ExtruderWidth { get; set; } = .4;
|
||||
|
||||
private List<List<int>> featureStartIndex = new List<List<int>>();
|
||||
private List<List<int>> featureEndIndex = new List<List<int>>();
|
||||
private List<List<RenderFeatureBase>> renderFeatures = new List<List<RenderFeatureBase>>();
|
||||
|
||||
public static RGBA_Bytes ExtrusionColor = RGBA_Bytes.White;
|
||||
public static RGBA_Bytes TravelColor = RGBA_Bytes.Green;
|
||||
|
||||
private GCodeFile gCodeFileToDraw;
|
||||
|
||||
public GCodeFile GCodeFileToDraw { get { return gCodeFileToDraw; } }
|
||||
|
||||
private ExtrusionColors extrusionColors;
|
||||
|
||||
public GCodeRenderer(GCodeFile gCodeFileToDraw)
|
||||
{
|
||||
if (gCodeFileToDraw != null)
|
||||
{
|
||||
this.gCodeFileToDraw = gCodeFileToDraw;
|
||||
|
||||
for (int i = 0; i < gCodeFileToDraw.NumChangesInZ; i++)
|
||||
{
|
||||
renderFeatures.Add(new List<RenderFeatureBase>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateFeaturesForLayerIfRequired(int layerToCreate)
|
||||
{
|
||||
if (extrusionColors == null
|
||||
&& gCodeFileToDraw != null
|
||||
&& gCodeFileToDraw.LineCount > 0)
|
||||
{
|
||||
extrusionColors = new ExtrusionColors();
|
||||
HashSet<float> speeds = new HashSet<float>();
|
||||
PrinterMachineInstruction prevInstruction = gCodeFileToDraw.Instruction(0);
|
||||
for (int i = 1; i < gCodeFileToDraw.LineCount; i++)
|
||||
{
|
||||
PrinterMachineInstruction instruction = gCodeFileToDraw.Instruction(i);
|
||||
if (instruction.EPosition > prevInstruction.EPosition && (instruction.Line.IndexOf('X') != -1 || instruction.Line.IndexOf('Y') != -1))
|
||||
{
|
||||
speeds.Add((float)instruction.FeedRate);
|
||||
}
|
||||
|
||||
prevInstruction = instruction;
|
||||
}
|
||||
|
||||
foreach (float speed in speeds)
|
||||
{
|
||||
extrusionColors.GetColorForSpeed(speed);
|
||||
}
|
||||
}
|
||||
|
||||
if (renderFeatures.Count == 0
|
||||
|| renderFeatures[layerToCreate].Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<RenderFeatureBase> renderFeaturesForLayer = renderFeatures[layerToCreate];
|
||||
|
||||
int startRenderIndex = gCodeFileToDraw.GetInstructionIndexAtLayer(layerToCreate);
|
||||
int endRenderIndex = gCodeFileToDraw.LineCount - 1;
|
||||
if (layerToCreate < gCodeFileToDraw.NumChangesInZ - 1)
|
||||
{
|
||||
endRenderIndex = gCodeFileToDraw.GetInstructionIndexAtLayer(layerToCreate + 1);
|
||||
}
|
||||
|
||||
for (int instructionIndex = startRenderIndex; instructionIndex < endRenderIndex; instructionIndex++)
|
||||
{
|
||||
PrinterMachineInstruction currentInstruction = gCodeFileToDraw.Instruction(instructionIndex);
|
||||
PrinterMachineInstruction previousInstruction = currentInstruction;
|
||||
if (instructionIndex > 0)
|
||||
{
|
||||
previousInstruction = gCodeFileToDraw.Instruction(instructionIndex - 1);
|
||||
}
|
||||
|
||||
if (currentInstruction.Position == previousInstruction.Position)
|
||||
{
|
||||
if (Math.Abs(currentInstruction.EPosition - previousInstruction.EPosition) > 0)
|
||||
{
|
||||
// this is a retraction
|
||||
renderFeaturesForLayer.Add(new RenderFeatureRetract(currentInstruction.Position, currentInstruction.EPosition - previousInstruction.EPosition, currentInstruction.ExtruderIndex, currentInstruction.FeedRate));
|
||||
}
|
||||
if (currentInstruction.Line.StartsWith("G10"))
|
||||
{
|
||||
renderFeaturesForLayer.Add(new RenderFeatureRetract(currentInstruction.Position, -1, currentInstruction.ExtruderIndex, currentInstruction.FeedRate));
|
||||
}
|
||||
else if (currentInstruction.Line.StartsWith("G11"))
|
||||
{
|
||||
renderFeaturesForLayer.Add(new RenderFeatureRetract(currentInstruction.Position, 1, currentInstruction.ExtruderIndex, currentInstruction.FeedRate));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gCodeFileToDraw.IsExtruding(instructionIndex))
|
||||
{
|
||||
double layerThickness = gCodeFileToDraw.GetLayerHeight();
|
||||
if (layerToCreate == 0)
|
||||
{
|
||||
layerThickness = gCodeFileToDraw.GetFirstLayerHeight();
|
||||
}
|
||||
|
||||
RGBA_Bytes extrusionColor = extrusionColors.GetColorForSpeed((float)currentInstruction.FeedRate);
|
||||
renderFeaturesForLayer.Add(new RenderFeatureExtrusion(previousInstruction.Position, currentInstruction.Position, currentInstruction.ExtruderIndex, currentInstruction.FeedRate, currentInstruction.EPosition - previousInstruction.EPosition, gCodeFileToDraw.GetFilamentDiameter(), layerThickness, extrusionColor));
|
||||
}
|
||||
else
|
||||
{
|
||||
renderFeaturesForLayer.Add(new RenderFeatureTravel(previousInstruction.Position, currentInstruction.Position, currentInstruction.ExtruderIndex, currentInstruction.FeedRate));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int GetNumFeatures(int layerToCountFeaturesOn)
|
||||
{
|
||||
CreateFeaturesForLayerIfRequired(layerToCountFeaturesOn);
|
||||
return renderFeatures[layerToCountFeaturesOn].Count;
|
||||
}
|
||||
|
||||
public void Render(Graphics2D graphics2D, GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if (renderFeatures.Count > 0)
|
||||
{
|
||||
CreateFeaturesForLayerIfRequired(renderInfo.EndLayerIndex);
|
||||
|
||||
int featuresOnLayer = renderFeatures[renderInfo.EndLayerIndex].Count;
|
||||
int endFeature = (int)(featuresOnLayer * renderInfo.FeatureToEndOnRatio0To1 + .5);
|
||||
endFeature = Math.Max(0, Math.Min(endFeature, featuresOnLayer));
|
||||
|
||||
int startFeature = (int)(featuresOnLayer * renderInfo.FeatureToStartOnRatio0To1 + .5);
|
||||
startFeature = Math.Max(0, Math.Min(startFeature, featuresOnLayer));
|
||||
|
||||
// try to make sure we always draw at least one feature
|
||||
if (endFeature <= startFeature)
|
||||
{
|
||||
endFeature = Math.Min(startFeature + 1, featuresOnLayer);
|
||||
}
|
||||
if (startFeature >= endFeature)
|
||||
{
|
||||
// This can only happen if the start and end are set to the last feature
|
||||
// Try to set the start feature to one from the end
|
||||
startFeature = Math.Max(endFeature - 1, 0);
|
||||
}
|
||||
|
||||
Graphics2DOpenGL graphics2DGl = graphics2D as Graphics2DOpenGL;
|
||||
if (graphics2DGl != null)
|
||||
{
|
||||
graphics2DGl.PreRender();
|
||||
GL.Begin(BeginMode.Triangles);
|
||||
for (int i = startFeature; i < endFeature; i++)
|
||||
{
|
||||
RenderFeatureBase feature = renderFeatures[renderInfo.EndLayerIndex][i];
|
||||
if (feature != null)
|
||||
{
|
||||
feature.Render(graphics2DGl, renderInfo);
|
||||
}
|
||||
}
|
||||
GL.End();
|
||||
graphics2DGl.PopOrthoProjection();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = startFeature; i < endFeature; i++)
|
||||
{
|
||||
RenderFeatureBase feature = renderFeatures[renderInfo.EndLayerIndex][i];
|
||||
if (feature != null)
|
||||
{
|
||||
feature.Render(graphics2D, renderInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Create3DDataForLayer(int layerIndex,
|
||||
VectorPOD<ColorVertexData> colorVertexData,
|
||||
VectorPOD<int> vertexIndexArray,
|
||||
GCodeRenderInfo renderInfo)
|
||||
{
|
||||
colorVertexData.Clear();
|
||||
vertexIndexArray.Clear();
|
||||
featureStartIndex[layerIndex].Clear();
|
||||
featureEndIndex[layerIndex].Clear();
|
||||
|
||||
for (int i = 0; i < renderFeatures[layerIndex].Count; i++)
|
||||
{
|
||||
featureStartIndex[layerIndex].Add(vertexIndexArray.Count);
|
||||
RenderFeatureBase feature = renderFeatures[layerIndex][i];
|
||||
if (feature != null)
|
||||
{
|
||||
feature.CreateRender3DData(colorVertexData, vertexIndexArray, renderInfo);
|
||||
}
|
||||
featureEndIndex[layerIndex].Add(vertexIndexArray.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Clear3DGCode();
|
||||
}
|
||||
|
||||
public void Clear3DGCode()
|
||||
{
|
||||
if (layerVertexBuffer != null)
|
||||
{
|
||||
for (int i = 0; i < layerVertexBuffer.Count; i++)
|
||||
{
|
||||
if (layerVertexBuffer[i] != null)
|
||||
{
|
||||
layerVertexBuffer[i].Dispose();
|
||||
layerVertexBuffer[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<GCodeVertexBuffer> layerVertexBuffer;
|
||||
private RenderType lastRenderType = RenderType.None;
|
||||
|
||||
private static readonly bool Is32Bit = IntPtr.Size == 4;
|
||||
|
||||
public void Render3D(GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if (layerVertexBuffer == null)
|
||||
{
|
||||
layerVertexBuffer = new List<GCodeVertexBuffer>();
|
||||
layerVertexBuffer.Capacity = gCodeFileToDraw.NumChangesInZ;
|
||||
for (int layerIndex = 0; layerIndex < gCodeFileToDraw.NumChangesInZ; layerIndex++)
|
||||
{
|
||||
layerVertexBuffer.Add(null);
|
||||
featureStartIndex.Add(new List<int>());
|
||||
featureEndIndex.Add(new List<int>());
|
||||
}
|
||||
}
|
||||
|
||||
for (int layerIndex = 0; layerIndex < gCodeFileToDraw.NumChangesInZ; layerIndex++)
|
||||
{
|
||||
CreateFeaturesForLayerIfRequired(layerIndex);
|
||||
}
|
||||
|
||||
if (lastRenderType != renderInfo.CurrentRenderType)
|
||||
{
|
||||
Clear3DGCode();
|
||||
lastRenderType = renderInfo.CurrentRenderType;
|
||||
}
|
||||
|
||||
if (renderFeatures.Count > 0)
|
||||
{
|
||||
if (Is32Bit && !GL.GlHasBufferObjects)
|
||||
{
|
||||
int maxFeaturesForThisSystem = 125000;
|
||||
int totalFeaturesToRunder = 0;
|
||||
bool cleanUnusedLayers = false;
|
||||
// if on 32 bit system make sure we don't run out of memory rendering too many features
|
||||
for (int i = renderInfo.EndLayerIndex - 1; i >= renderInfo.StartLayerIndex; i--)
|
||||
{
|
||||
if (totalFeaturesToRunder + renderFeatures[i].Count < maxFeaturesForThisSystem)
|
||||
{
|
||||
totalFeaturesToRunder += renderFeatures[i].Count;
|
||||
}
|
||||
else // don't render any of the layers below this and in fact remove them from memory if possible
|
||||
{
|
||||
renderInfo.startLayerIndex = i + 1;
|
||||
cleanUnusedLayers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanUnusedLayers)
|
||||
{
|
||||
// no remove any layers that are set that we are not going to render
|
||||
for (int removeIndex = 0; removeIndex < layerVertexBuffer.Count; removeIndex++)
|
||||
{
|
||||
if (removeIndex < renderInfo.StartLayerIndex || removeIndex >= renderInfo.EndLayerIndex)
|
||||
{
|
||||
if (layerVertexBuffer[removeIndex] != null)
|
||||
{
|
||||
layerVertexBuffer[removeIndex].Dispose();
|
||||
layerVertexBuffer[removeIndex] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = renderInfo.EndLayerIndex - 1; i >= renderInfo.StartLayerIndex; i--)
|
||||
{
|
||||
// If its the first render or we change what we are trying to render then create vertex data.
|
||||
if (layerVertexBuffer[i] == null)
|
||||
{
|
||||
VectorPOD<ColorVertexData> colorVertexData = new VectorPOD<ColorVertexData>();
|
||||
VectorPOD<int> vertexIndexArray = new VectorPOD<int>();
|
||||
|
||||
Create3DDataForLayer(i, colorVertexData, vertexIndexArray, renderInfo);
|
||||
|
||||
layerVertexBuffer[i] = new GCodeVertexBuffer();
|
||||
layerVertexBuffer[i].SetVertexData(colorVertexData.Array);
|
||||
layerVertexBuffer[i].SetIndexData(vertexIndexArray.Array);
|
||||
}
|
||||
}
|
||||
|
||||
GL.Disable(EnableCap.Texture2D);
|
||||
GL.PushAttrib(AttribMask.EnableBit);
|
||||
GL.DisableClientState(ArrayCap.TextureCoordArray);
|
||||
GL.Enable(EnableCap.PolygonSmooth);
|
||||
|
||||
if (renderInfo.EndLayerIndex - 1 > renderInfo.StartLayerIndex)
|
||||
{
|
||||
for (int i = renderInfo.StartLayerIndex; i < renderInfo.EndLayerIndex - 1; i++)
|
||||
{
|
||||
int featuresOnLayer = renderFeatures[i].Count;
|
||||
if (featuresOnLayer > 1)
|
||||
{
|
||||
layerVertexBuffer[i].renderRange(0, featureEndIndex[i][featuresOnLayer - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw the partial layer of end-1 from startRatio to endRatio
|
||||
{
|
||||
int layerIndex = renderInfo.EndLayerIndex - 1;
|
||||
int featuresOnLayer = renderFeatures[layerIndex].Count;
|
||||
int startFeature = (int)(featuresOnLayer * renderInfo.FeatureToStartOnRatio0To1 + .5);
|
||||
startFeature = Math.Max(0, Math.Min(startFeature, featuresOnLayer));
|
||||
|
||||
int endFeature = (int)(featuresOnLayer * renderInfo.FeatureToEndOnRatio0To1 + .5);
|
||||
endFeature = Math.Max(0, Math.Min(endFeature, featuresOnLayer));
|
||||
|
||||
// try to make sure we always draw at least one feature
|
||||
if (endFeature <= startFeature)
|
||||
{
|
||||
endFeature = Math.Min(startFeature + 1, featuresOnLayer);
|
||||
}
|
||||
if (startFeature >= endFeature)
|
||||
{
|
||||
// This can only happen if the start and end are set to the last feature
|
||||
// Try to set the start feature to one from the end
|
||||
startFeature = Math.Max(endFeature - 1, 0);
|
||||
}
|
||||
|
||||
if (endFeature > startFeature)
|
||||
{
|
||||
int ellementCount = featureEndIndex[layerIndex][endFeature - 1] - featureStartIndex[layerIndex][startFeature];
|
||||
|
||||
layerVertexBuffer[layerIndex].renderRange(featureStartIndex[layerIndex][startFeature], ellementCount);
|
||||
}
|
||||
}
|
||||
GL.PopAttrib();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
136
MatterControl.OpenGL/GCodeRenderer/GCodeVertexBuffer.cs
Normal file
136
MatterControl.OpenGL/GCodeRenderer/GCodeVertexBuffer.cs
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.RenderOpenGl.OpenGl;
|
||||
|
||||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public class GCodeVertexBuffer : IDisposable
|
||||
{
|
||||
public int myIndexId;
|
||||
public int myIndexLength;
|
||||
public BeginMode myMode = BeginMode.Triangles;
|
||||
public int myVertexId;
|
||||
public int myVertexLength;
|
||||
public GCodeVertexBuffer()
|
||||
{
|
||||
GL.GenBuffers(1, out myVertexId);
|
||||
GL.GenBuffers(1, out myIndexId);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (myVertexId != -1)
|
||||
{
|
||||
int holdVertexId = myVertexId;
|
||||
int holdIndexId = myIndexId;
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
GL.DeleteBuffers(1, ref holdVertexId);
|
||||
GL.DeleteBuffers(1, ref holdIndexId);
|
||||
});
|
||||
|
||||
myVertexId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
~GCodeVertexBuffer()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void renderRange(int offset, int count)
|
||||
{
|
||||
GL.EnableClientState(ArrayCap.ColorArray);
|
||||
GL.EnableClientState(ArrayCap.NormalArray);
|
||||
GL.EnableClientState(ArrayCap.VertexArray);
|
||||
GL.DisableClientState(ArrayCap.TextureCoordArray);
|
||||
GL.Disable(EnableCap.Texture2D);
|
||||
|
||||
GL.EnableClientState(ArrayCap.IndexArray);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, myVertexId);
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, myIndexId);
|
||||
|
||||
GL.ColorPointer(4, ColorPointerType.UnsignedByte, ColorVertexData.Stride, new IntPtr(0));
|
||||
GL.NormalPointer(NormalPointerType.Float, ColorVertexData.Stride, new IntPtr(4));
|
||||
GL.VertexPointer(3, VertexPointerType.Float, ColorVertexData.Stride, new IntPtr(4 + 3 * 4));
|
||||
|
||||
GL.DrawRangeElements(myMode, 0, myIndexLength, count, DrawElementsType.UnsignedInt, new IntPtr(offset * 4));
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
|
||||
|
||||
GL.DisableClientState(ArrayCap.IndexArray);
|
||||
|
||||
GL.DisableClientState(ArrayCap.VertexArray);
|
||||
GL.DisableClientState(ArrayCap.NormalArray);
|
||||
GL.DisableClientState(ArrayCap.ColorArray);
|
||||
}
|
||||
|
||||
public void SetIndexData(int[] data)
|
||||
{
|
||||
SetIndexData(data, data.Length);
|
||||
}
|
||||
|
||||
public void SetIndexData(int[] data, int count)
|
||||
{
|
||||
myIndexLength = count;
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, myIndexId);
|
||||
unsafe
|
||||
{
|
||||
fixed (int* dataPointer = data)
|
||||
{
|
||||
GL.BufferData(BufferTarget.ElementArrayBuffer, data.Length * sizeof(int), (IntPtr)dataPointer, BufferUsageHint.StaticDraw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVertexData(ColorVertexData[] data)
|
||||
{
|
||||
SetVertexData(data, data.Length);
|
||||
}
|
||||
|
||||
public void SetVertexData(ColorVertexData[] data, int count)
|
||||
{
|
||||
myVertexLength = count;
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, myVertexId);
|
||||
unsafe
|
||||
{
|
||||
fixed (ColorVertexData* dataPointer = data)
|
||||
{
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, data.Length * ColorVertexData.Stride, (IntPtr)dataPointer, BufferUsageHint.StaticDraw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public abstract class RenderFeatureBase
|
||||
{
|
||||
protected int extruderIndex;
|
||||
|
||||
public abstract void Render(Graphics2D graphics2D, GCodeRenderInfo renderInfo);
|
||||
|
||||
public abstract void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, GCodeRenderInfo renderInfo);
|
||||
|
||||
public RenderFeatureBase(int extruderIndex)
|
||||
{
|
||||
this.extruderIndex = extruderIndex;
|
||||
}
|
||||
|
||||
static public void CreateCylinder(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, Vector3 startPos, Vector3 endPos, double radius, int steps, RGBA_Bytes color, double layerHeight)
|
||||
{
|
||||
Vector3 direction = endPos - startPos;
|
||||
Vector3 directionNormal = direction.GetNormal();
|
||||
Vector3 startSweepDirection = Vector3.GetPerpendicular(startPos, endPos).GetNormal();
|
||||
|
||||
int[] tubeStartIndices = new int[steps];
|
||||
int[] tubeEndIndices = new int[steps];
|
||||
|
||||
int[] capStartIndices = new int[steps];
|
||||
int[] capEndIndices = new int[steps];
|
||||
|
||||
double halfHeight = layerHeight / 2 + (layerHeight * .1);
|
||||
double halfWidth = radius;
|
||||
double zScale = halfHeight / radius;
|
||||
double xScale = halfWidth / radius;
|
||||
|
||||
Vector3 scale = new Vector3(xScale, xScale, zScale);
|
||||
|
||||
for (int i = 0; i < steps; i++)
|
||||
{
|
||||
// create tube ends verts
|
||||
Vector3 tubeNormal = Vector3.Transform(startSweepDirection, Matrix4X4.CreateRotation(direction, MathHelper.Tau / (steps * 2) + MathHelper.Tau / (steps) * i));
|
||||
Vector3 offset = Vector3.Transform(startSweepDirection * radius, Matrix4X4.CreateRotation(direction, MathHelper.Tau / (steps * 2) + MathHelper.Tau / (steps) * i));
|
||||
offset *= scale;
|
||||
|
||||
Vector3 tubeStart = startPos + offset;
|
||||
tubeStartIndices[i] = colorVertexData.Count;
|
||||
colorVertexData.Add(new ColorVertexData(tubeStart, tubeNormal, color));
|
||||
|
||||
Vector3 tubeEnd = endPos + offset;
|
||||
tubeEndIndices[i] = colorVertexData.Count;
|
||||
colorVertexData.Add(new ColorVertexData(tubeEnd, tubeNormal, color));
|
||||
|
||||
// create cap verts
|
||||
Vector3 rotateAngle = Vector3.Cross(direction, startSweepDirection);
|
||||
Vector3 capStartNormal = Vector3.Transform(startSweepDirection, Matrix4X4.CreateRotation(rotateAngle, MathHelper.Tau / 8));
|
||||
capStartNormal = Vector3.Transform(capStartNormal, Matrix4X4.CreateRotation(direction, MathHelper.Tau / (steps * 2) + MathHelper.Tau / (steps) * i));
|
||||
capStartNormal = (capStartNormal * scale).GetNormal();
|
||||
Vector3 capStartOffset = capStartNormal * radius;
|
||||
capStartOffset *= scale;
|
||||
Vector3 capStart = startPos + capStartOffset;
|
||||
capStartIndices[i] = colorVertexData.Count;
|
||||
colorVertexData.Add(new ColorVertexData(capStart, capStartNormal, color));
|
||||
|
||||
Vector3 capEndNormal = Vector3.Transform(startSweepDirection, Matrix4X4.CreateRotation(-rotateAngle, MathHelper.Tau / 8));
|
||||
capEndNormal = Vector3.Transform(capEndNormal, Matrix4X4.CreateRotation(direction, MathHelper.Tau / (steps * 2) + MathHelper.Tau / (steps) * i));
|
||||
capEndNormal = (capEndNormal * scale).GetNormal();
|
||||
Vector3 capEndOffset = capEndNormal * radius;
|
||||
capEndOffset *= scale;
|
||||
Vector3 capEnd = endPos + capEndOffset;
|
||||
capEndIndices[i] = colorVertexData.Count;
|
||||
colorVertexData.Add(new ColorVertexData(capEnd, capEndNormal, color));
|
||||
}
|
||||
|
||||
int tipStartIndex = colorVertexData.Count;
|
||||
Vector3 tipOffset = directionNormal * radius;
|
||||
tipOffset *= scale;
|
||||
colorVertexData.Add(new ColorVertexData(startPos - tipOffset, -directionNormal, color));
|
||||
int tipEndIndex = colorVertexData.Count;
|
||||
colorVertexData.Add(new ColorVertexData(endPos + tipOffset, directionNormal, color));
|
||||
|
||||
for (int i = 0; i < steps; i++)
|
||||
{
|
||||
// create tube polys
|
||||
indexData.Add(tubeStartIndices[i]);
|
||||
indexData.Add(tubeEndIndices[i]);
|
||||
indexData.Add(tubeEndIndices[(i + 1) % steps]);
|
||||
|
||||
indexData.Add(tubeStartIndices[i]);
|
||||
indexData.Add(tubeEndIndices[(i + 1) % steps]);
|
||||
indexData.Add(tubeStartIndices[(i + 1) % steps]);
|
||||
|
||||
// create start cap polys
|
||||
indexData.Add(tubeStartIndices[i]);
|
||||
indexData.Add(capStartIndices[i]);
|
||||
indexData.Add(capStartIndices[(i + 1) % steps]);
|
||||
|
||||
indexData.Add(tubeStartIndices[i]);
|
||||
indexData.Add(capStartIndices[(i + 1) % steps]);
|
||||
indexData.Add(tubeStartIndices[(i + 1) % steps]);
|
||||
|
||||
// create end cap polys
|
||||
indexData.Add(tubeEndIndices[i]);
|
||||
indexData.Add(capEndIndices[i]);
|
||||
indexData.Add(capEndIndices[(i + 1) % steps]);
|
||||
|
||||
indexData.Add(tubeEndIndices[i]);
|
||||
indexData.Add(capEndIndices[(i + 1) % steps]);
|
||||
indexData.Add(tubeEndIndices[(i + 1) % steps]);
|
||||
|
||||
// create start tip polys
|
||||
indexData.Add(tipStartIndex);
|
||||
indexData.Add(capStartIndices[i]);
|
||||
indexData.Add(capStartIndices[(i + 1) % steps]);
|
||||
|
||||
// create end tip polys
|
||||
indexData.Add(tipEndIndex);
|
||||
indexData.Add(capEndIndices[i]);
|
||||
indexData.Add(capEndIndices[(i + 1) % steps]);
|
||||
}
|
||||
}
|
||||
|
||||
static public void CreatePointer(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, Vector3 startPos, Vector3 endPos, double radius, int steps, RGBA_Bytes color)
|
||||
{
|
||||
Vector3 direction = endPos - startPos;
|
||||
Vector3 directionNormal = direction.GetNormal();
|
||||
Vector3 startSweepDirection = Vector3.GetPerpendicular(startPos, endPos).GetNormal();
|
||||
|
||||
int[] tubeStartIndices = new int[steps];
|
||||
|
||||
for (int i = 0; i < steps; i++)
|
||||
{
|
||||
// create tube ends verts
|
||||
Vector3 tubeNormal = Vector3.Transform(startSweepDirection, Matrix4X4.CreateRotation(direction, MathHelper.Tau / (steps * 2) + MathHelper.Tau / (steps) * i));
|
||||
Vector3 offset = Vector3.Transform(startSweepDirection * radius, Matrix4X4.CreateRotation(direction, MathHelper.Tau / (steps * 2) + MathHelper.Tau / (steps) * i));
|
||||
Vector3 tubeStart = startPos + offset;
|
||||
tubeStartIndices[i] = colorVertexData.Count;
|
||||
colorVertexData.Add(new ColorVertexData(tubeStart, tubeNormal, color));
|
||||
Vector3 tubeEnd = endPos + offset;
|
||||
}
|
||||
|
||||
int tipEndIndex = colorVertexData.Count;
|
||||
colorVertexData.Add(new ColorVertexData(endPos, directionNormal, color));
|
||||
|
||||
for (int i = 0; i < steps; i++)
|
||||
{
|
||||
// create tube polys
|
||||
indexData.Add(tubeStartIndices[i]);
|
||||
indexData.Add(tubeStartIndices[(i + 1) % steps]);
|
||||
|
||||
indexData.Add(tipEndIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public class RenderFeatureExtrusion : RenderFeatureTravel
|
||||
{
|
||||
private float extrusionVolumeMm3;
|
||||
private float layerHeight;
|
||||
private RGBA_Bytes color;
|
||||
|
||||
public RenderFeatureExtrusion(Vector3 start, Vector3 end, int extruderIndex, double travelSpeed, double totalExtrusionMm, double filamentDiameterMm, double layerHeight, RGBA_Bytes color)
|
||||
: base(start, end, extruderIndex, travelSpeed)
|
||||
{
|
||||
this.color = color;
|
||||
double filamentRadius = filamentDiameterMm / 2;
|
||||
double areaSquareMm = (filamentRadius * filamentRadius) * Math.PI;
|
||||
|
||||
this.extrusionVolumeMm3 = (float)(areaSquareMm * totalExtrusionMm);
|
||||
this.layerHeight = (float)layerHeight;
|
||||
}
|
||||
|
||||
private double GetRadius(RenderType renderType)
|
||||
{
|
||||
return GetExtrusionWidth(renderType) / 2;
|
||||
}
|
||||
|
||||
private double GetExtrusionWidth(RenderType renderType)
|
||||
{
|
||||
double width = GCodeRenderer.ExtruderWidth;
|
||||
if ((renderType & RenderType.SimulateExtrusion) == RenderType.SimulateExtrusion)
|
||||
{
|
||||
double moveLength = (end - start).Length;
|
||||
|
||||
if (moveLength > .1) // we get truncation errors from the slice engine when the length is very small, so don't do them
|
||||
{
|
||||
double area = extrusionVolumeMm3 / moveLength;
|
||||
width = area / layerHeight;
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
public override void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if ((renderInfo.CurrentRenderType & RenderType.Extrusions) == RenderType.Extrusions)
|
||||
{
|
||||
Vector3Float start = this.GetStart(renderInfo);
|
||||
Vector3Float end = this.GetEnd(renderInfo);
|
||||
double radius = GetRadius(renderInfo.CurrentRenderType);
|
||||
if ((renderInfo.CurrentRenderType & RenderType.SpeedColors) == RenderType.SpeedColors)
|
||||
{
|
||||
CreateCylinder(colorVertexData, indexData, new Vector3(start), new Vector3(end), radius, 6, color, layerHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (extruderIndex == 0)
|
||||
{
|
||||
CreateCylinder(colorVertexData, indexData, new Vector3(start), new Vector3(end), radius, 6, GCodeRenderer.ExtrusionColor, layerHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateCylinder(colorVertexData, indexData, new Vector3(start), new Vector3(end), radius, 6, renderInfo.GetMaterialColor(extruderIndex + 1), layerHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Render(Graphics2D graphics2D, GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if (renderInfo.CurrentRenderType.HasFlag(RenderType.Extrusions))
|
||||
{
|
||||
double extrusionLineWidths = GetExtrusionWidth(renderInfo.CurrentRenderType) * 2 * renderInfo.LayerScale;
|
||||
|
||||
RGBA_Bytes extrusionColor = RGBA_Bytes.Black;
|
||||
if (extruderIndex > 0)
|
||||
{
|
||||
extrusionColor = renderInfo.GetMaterialColor(extruderIndex + 1);
|
||||
}
|
||||
if (renderInfo.CurrentRenderType.HasFlag(RenderType.SpeedColors))
|
||||
{
|
||||
extrusionColor = color;
|
||||
}
|
||||
|
||||
if (renderInfo.CurrentRenderType.HasFlag(RenderType.TransparentExtrusion))
|
||||
{
|
||||
extrusionColor = new RGBA_Bytes(extrusionColor, 200);
|
||||
}
|
||||
|
||||
// render the part using opengl
|
||||
Graphics2DOpenGL graphics2DGl = graphics2D as Graphics2DOpenGL;
|
||||
if (graphics2DGl != null)
|
||||
{
|
||||
Vector3Float startF = this.GetStart(renderInfo);
|
||||
Vector3Float endF = this.GetEnd(renderInfo);
|
||||
Vector2 start = new Vector2(startF.x, startF.y);
|
||||
renderInfo.Transform.transform(ref start);
|
||||
|
||||
Vector2 end = new Vector2(endF.x, endF.y);
|
||||
renderInfo.Transform.transform(ref end);
|
||||
|
||||
graphics2DGl.DrawAALineRounded(start, end, extrusionLineWidths/2, extrusionColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
PathStorage pathStorage = new PathStorage();
|
||||
VertexSourceApplyTransform transformedPathStorage = new VertexSourceApplyTransform(pathStorage, renderInfo.Transform);
|
||||
Stroke stroke = new Stroke(transformedPathStorage, extrusionLineWidths/2);
|
||||
|
||||
stroke.line_cap(LineCap.Round);
|
||||
stroke.line_join(LineJoin.Round);
|
||||
|
||||
Vector3Float start = this.GetStart(renderInfo);
|
||||
Vector3Float end = this.GetEnd(renderInfo);
|
||||
|
||||
pathStorage.Add(start.x, start.y, ShapePath.FlagsAndCommand.CommandMoveTo);
|
||||
pathStorage.Add(end.x, end.y, ShapePath.FlagsAndCommand.CommandLineTo);
|
||||
|
||||
graphics2D.Render(stroke, 0, extrusionColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public class RenderFeatureRetract : RenderFeatureBase
|
||||
{
|
||||
public static double RetractionDrawRadius = 1;
|
||||
|
||||
private float extrusionAmount;
|
||||
private float mmPerSecond;
|
||||
private Vector3Float position;
|
||||
|
||||
public RenderFeatureRetract(Vector3 position, double extrusionAmount, int extruderIndex, double mmPerSecond)
|
||||
: base(extruderIndex)
|
||||
{
|
||||
this.extrusionAmount = (float)extrusionAmount;
|
||||
this.mmPerSecond = (float)mmPerSecond;
|
||||
|
||||
this.position = new Vector3Float(position);
|
||||
}
|
||||
|
||||
private double Radius(double layerScale)
|
||||
{
|
||||
double radius = RetractionDrawRadius * layerScale;
|
||||
double area = Math.PI * radius * radius;
|
||||
area *= Math.Abs(extrusionAmount);
|
||||
radius = Math.Sqrt(area / Math.PI);
|
||||
return radius;
|
||||
}
|
||||
|
||||
public override void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if ((renderInfo.CurrentRenderType & RenderType.Retractions) == RenderType.Retractions)
|
||||
{
|
||||
Vector3 position = new Vector3(this.position);
|
||||
|
||||
if (renderInfo.CurrentRenderType.HasFlag(RenderType.HideExtruderOffsets))
|
||||
{
|
||||
Vector2 offset = renderInfo.GetExtruderOffset(extruderIndex);
|
||||
position = position + new Vector3(offset);
|
||||
}
|
||||
|
||||
RGBA_Bytes color = renderInfo.GetMaterialColor(extruderIndex + 1);
|
||||
if (extruderIndex == 0)
|
||||
{
|
||||
if (extrusionAmount > 0)
|
||||
{
|
||||
color = RGBA_Bytes.Blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = RGBA_Bytes.Red;
|
||||
}
|
||||
}
|
||||
if (extrusionAmount > 0)
|
||||
{
|
||||
// unretraction
|
||||
CreatePointer(colorVertexData, indexData, position + new Vector3(0, 0, 1.3), position + new Vector3(0, 0, .3), Radius(1), 5, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
// retraction
|
||||
CreatePointer(colorVertexData, indexData, position + new Vector3(0, 0, .3), position + new Vector3(0, 0, 1.3), Radius(1), 5, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Render(Graphics2D graphics2D, GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if ((renderInfo.CurrentRenderType & RenderType.Retractions) == RenderType.Retractions)
|
||||
{
|
||||
double radius = Radius(renderInfo.LayerScale);
|
||||
Vector2 position = new Vector2(this.position.x, this.position.y);
|
||||
|
||||
if (renderInfo.CurrentRenderType.HasFlag(RenderType.HideExtruderOffsets))
|
||||
{
|
||||
Vector2 offset = renderInfo.GetExtruderOffset(extruderIndex);
|
||||
position = position + offset;
|
||||
}
|
||||
|
||||
renderInfo.Transform.transform(ref position);
|
||||
|
||||
RGBA_Bytes retractionColor = new RGBA_Bytes(RGBA_Bytes.Red, 200);
|
||||
if (extrusionAmount > 0)
|
||||
{
|
||||
// unretraction
|
||||
retractionColor = new RGBA_Bytes(RGBA_Bytes.Blue, 200);
|
||||
}
|
||||
|
||||
// render the part using opengl
|
||||
Graphics2DOpenGL graphics2DGl = graphics2D as Graphics2DOpenGL;
|
||||
if (graphics2DGl != null)
|
||||
{
|
||||
graphics2DGl.DrawAACircle(position, radius, retractionColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ellipse extrusion = new Ellipse(position, radius);
|
||||
graphics2D.Render(extrusion, retractionColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public class RenderFeatureTravel : RenderFeatureBase
|
||||
{
|
||||
protected Vector3Float start;
|
||||
protected Vector3Float end;
|
||||
protected float travelSpeed;
|
||||
|
||||
protected Vector3Float GetStart(GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if (renderInfo.CurrentRenderType.HasFlag(RenderType.HideExtruderOffsets))
|
||||
{
|
||||
Vector3Float start = this.start;
|
||||
Vector2 offset = renderInfo.GetExtruderOffset(extruderIndex);
|
||||
start.x += (float)offset.x;
|
||||
start.y += (float)offset.y;
|
||||
return start;
|
||||
}
|
||||
|
||||
return this.start;
|
||||
}
|
||||
|
||||
protected Vector3Float GetEnd(GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if (renderInfo.CurrentRenderType.HasFlag(RenderType.HideExtruderOffsets))
|
||||
{
|
||||
Vector3Float end = this.end;
|
||||
Vector2 offset = renderInfo.GetExtruderOffset(extruderIndex);
|
||||
end.x += (float)offset.x;
|
||||
end.y += (float)offset.y;
|
||||
return end;
|
||||
}
|
||||
|
||||
return this.end;
|
||||
}
|
||||
|
||||
public RenderFeatureTravel(Vector3 start, Vector3 end, int extruderIndex, double travelSpeed)
|
||||
: base(extruderIndex)
|
||||
{
|
||||
this.extruderIndex = extruderIndex;
|
||||
this.start = new Vector3Float(start);
|
||||
this.end = new Vector3Float(end);
|
||||
this.travelSpeed = (float)travelSpeed;
|
||||
}
|
||||
|
||||
public override void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if ((renderInfo.CurrentRenderType & RenderType.Moves) == RenderType.Moves)
|
||||
{
|
||||
Vector3Float start = this.GetStart(renderInfo);
|
||||
Vector3Float end = this.GetEnd(renderInfo);
|
||||
CreateCylinder(colorVertexData, indexData, new Vector3(start), new Vector3(end), .1, 6, GCodeRenderer.TravelColor, .2);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Render(Graphics2D graphics2D, GCodeRenderInfo renderInfo)
|
||||
{
|
||||
if ((renderInfo.CurrentRenderType & RenderType.Moves) == RenderType.Moves)
|
||||
{
|
||||
double movementLineWidth = 0.35 * renderInfo.LayerScale;
|
||||
RGBA_Bytes movementColor = new RGBA_Bytes(10, 190, 15);
|
||||
|
||||
// render the part using opengl
|
||||
Graphics2DOpenGL graphics2DGl = graphics2D as Graphics2DOpenGL;
|
||||
if (graphics2DGl != null)
|
||||
{
|
||||
Vector3Float startF = this.GetStart(renderInfo);
|
||||
Vector3Float endF = this.GetEnd(renderInfo);
|
||||
Vector2 start = new Vector2(startF.x, startF.y);
|
||||
renderInfo.Transform.transform(ref start);
|
||||
|
||||
Vector2 end = new Vector2(endF.x, endF.y);
|
||||
renderInfo.Transform.transform(ref end);
|
||||
|
||||
graphics2DGl.DrawAALineRounded(start, end, movementLineWidth, movementColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
PathStorage pathStorage = new PathStorage();
|
||||
VertexSourceApplyTransform transformedPathStorage = new VertexSourceApplyTransform(pathStorage, renderInfo.Transform);
|
||||
Stroke stroke = new Stroke(transformedPathStorage, movementLineWidth);
|
||||
|
||||
stroke.line_cap(LineCap.Round);
|
||||
stroke.line_join(LineJoin.Round);
|
||||
|
||||
Vector3Float start = this.GetStart(renderInfo);
|
||||
Vector3Float end = this.GetEnd(renderInfo);
|
||||
|
||||
pathStorage.Add(start.x, start.y, ShapePath.FlagsAndCommand.CommandMoveTo);
|
||||
if (end.x != start.x || end.y != start.y)
|
||||
{
|
||||
pathStorage.Add(end.x, end.y, ShapePath.FlagsAndCommand.CommandLineTo);
|
||||
}
|
||||
else
|
||||
{
|
||||
pathStorage.Add(end.x + .01, end.y, ShapePath.FlagsAndCommand.CommandLineTo);
|
||||
}
|
||||
|
||||
graphics2D.Render(stroke, 0, movementColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
MatterControl.OpenGL/MatterControl.OpenGL.csproj
Normal file
80
MatterControl.OpenGL/MatterControl.OpenGL.csproj
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{CBDEEC31-D688-417B-9BF2-F0DB2E4FB268}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MatterControl.OpenGL</RootNamespace>
|
||||
<AssemblyName>MatterControl.OpenGL</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="GCodeRenderer\ColorVertexData.cs" />
|
||||
<Compile Include="GCodeRenderer\ExtrusionColors.cs" />
|
||||
<Compile Include="GCodeRenderer\GCodeRenderer.cs" />
|
||||
<Compile Include="GCodeRenderer\GCodeRenderInfo.cs" />
|
||||
<Compile Include="GCodeRenderer\GCodeVertexBuffer.cs" />
|
||||
<Compile Include="GCodeRenderer\RenderFeatures\RenderFeatureBase.cs" />
|
||||
<Compile Include="GCodeRenderer\RenderFeatures\RenderFeatureExtrusion.cs" />
|
||||
<Compile Include="GCodeRenderer\RenderFeatures\RenderFeatureRetract.cs" />
|
||||
<Compile Include="GCodeRenderer\RenderFeatures\RenderFeatureTravel.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MatterControl.Printing\MatterControl.Printing.csproj">
|
||||
<Project>{97d5ade3-c1b4-4b46-8a3e-718a4f7f079f}</Project>
|
||||
<Name>MatterControl.Printing</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\agg\Agg.csproj">
|
||||
<Project>{657dbc6d-c3ea-4398-a3fa-ddb73c14f71b}</Project>
|
||||
<Name>Agg</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\Gui\Gui.csproj">
|
||||
<Project>{74f6bb6c-9d02-4512-a59a-21940e35c532}</Project>
|
||||
<Name>Gui</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\RenderOpenGl\RenderOpenGl.csproj">
|
||||
<Project>{545b6912-77ff-4b34-ba76-6c3d6a32be6a}</Project>
|
||||
<Name>RenderOpenGl</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\VectorMath\VectorMath.csproj">
|
||||
<Project>{d3e41b4e-bfbb-44ca-94c8-95c00f754fdd}</Project>
|
||||
<Name>VectorMath</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
36
MatterControl.OpenGL/Properties/AssemblyInfo.cs
Normal file
36
MatterControl.OpenGL/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MatterControl.OpenGL")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MatterControl.OpenGL")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("cbdeec31-d688-417b-9bf2-f0db2e4fb268")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
254
MatterControl.Printing/GCode/GCodeFile.cs
Normal file
254
MatterControl.Printing/GCode/GCodeFile.cs
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
Copyright (c) 2016, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.VectorMath;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public abstract class GCodeFile
|
||||
{
|
||||
private static readonly Vector4 MaxAccelerationMmPerS2 = new Vector4(1000, 1000, 100, 5000);
|
||||
private static readonly Vector4 MaxVelocityMmPerS = new Vector4(500, 500, 5, 25);
|
||||
private static readonly Vector4 VelocitySameAsStopMmPerS = new Vector4(8, 8, .4, 5);
|
||||
|
||||
#if __ANDROID__
|
||||
protected const int Max32BitFileSize = 10000000; // 10 megs
|
||||
#else
|
||||
protected const int Max32BitFileSize = 100000000; // 100 megs
|
||||
#endif
|
||||
|
||||
public static void AssertDebugNotDefined()
|
||||
{
|
||||
#if DEBUG
|
||||
throw new Exception("DEBUG is defined and should not be!");
|
||||
#endif
|
||||
}
|
||||
|
||||
#region Abstract Functions
|
||||
// the number of lines in the file
|
||||
public abstract int LineCount { get; }
|
||||
|
||||
public abstract int NumChangesInZ { get; }
|
||||
public abstract double TotalSecondsInPrint { get; }
|
||||
|
||||
public abstract void Clear();
|
||||
|
||||
public abstract RectangleDouble GetBounds();
|
||||
|
||||
public abstract double GetFilamentCubicMm(double filamentDiameter);
|
||||
|
||||
public abstract double GetFilamentDiameter();
|
||||
|
||||
public abstract double GetFilamentUsedMm(double filamentDiameter);
|
||||
|
||||
public abstract double GetFilamentWeightGrams(double filamentDiameterMm, double density);
|
||||
|
||||
public abstract double GetFirstLayerHeight();
|
||||
|
||||
public abstract int GetInstructionIndexAtLayer(int layerIndex);
|
||||
|
||||
public abstract double GetLayerHeight();
|
||||
|
||||
public abstract int GetLayerIndex(int instructionIndex);
|
||||
|
||||
public abstract Vector2 GetWeightedCenter();
|
||||
|
||||
public abstract PrinterMachineInstruction Instruction(int i);
|
||||
|
||||
public abstract bool IsExtruding(int instructionIndexToCheck);
|
||||
public abstract double PercentComplete(int instructionIndex);
|
||||
|
||||
public abstract double Ratio0to1IntoContainedLayer(int instructionIndex);
|
||||
#endregion Abstract Functions
|
||||
|
||||
#region Static Functions
|
||||
|
||||
public static int CalculateChecksum(string commandToGetChecksumFor)
|
||||
{
|
||||
int checksum = 0;
|
||||
if (commandToGetChecksumFor.Length > 0)
|
||||
{
|
||||
checksum = commandToGetChecksumFor[0];
|
||||
for (int i = 1; i < commandToGetChecksumFor.Length; i++)
|
||||
{
|
||||
checksum ^= commandToGetChecksumFor[i];
|
||||
}
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
public static bool IsLayerChange(string lineString)
|
||||
{
|
||||
return lineString.StartsWith("; LAYER:")
|
||||
|| lineString.StartsWith(";LAYER:");
|
||||
}
|
||||
|
||||
public static bool FileTooBigToLoad(string fileName)
|
||||
{
|
||||
if (File.Exists(fileName)
|
||||
&& Is32Bit)
|
||||
{
|
||||
FileInfo info = new FileInfo(fileName);
|
||||
// Let's make sure we can load a file this big
|
||||
if (info.Length > Max32BitFileSize)
|
||||
{
|
||||
// It is too big to load
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool GetFirstNumberAfter(string stringToCheckAfter, string stringWithNumber, ref int readValue, int startIndex = 0, string stopCheckingString = ";")
|
||||
{
|
||||
double doubleValue = readValue;
|
||||
if(GetFirstNumberAfter(stringToCheckAfter, stringWithNumber, ref doubleValue, startIndex, stopCheckingString))
|
||||
{
|
||||
readValue = (int)doubleValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool GetFirstNumberAfter(string stringToCheckAfter, string stringWithNumber, ref double readValue, int startIndex = 0, string stopCheckingString = ";")
|
||||
{
|
||||
int stringPos = stringWithNumber.IndexOf(stringToCheckAfter, startIndex);
|
||||
int stopPos = stringWithNumber.IndexOf(stopCheckingString);
|
||||
if (stringPos != -1
|
||||
&& (stopPos == -1 || stringPos < stopPos))
|
||||
{
|
||||
stringPos += stringToCheckAfter.Length;
|
||||
readValue = agg_basics.ParseDouble(stringWithNumber, ref stringPos, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool GetFirstStringAfter(string stringToCheckAfter, string fullStringToLookIn, string separatorString, ref string nextString, int startIndex = 0)
|
||||
{
|
||||
int stringPos = fullStringToLookIn.IndexOf(stringToCheckAfter, startIndex);
|
||||
if (stringPos != -1)
|
||||
{
|
||||
int separatorPos = fullStringToLookIn.IndexOf(separatorString, stringPos);
|
||||
if (separatorPos != -1)
|
||||
{
|
||||
nextString = fullStringToLookIn.Substring(stringPos + stringToCheckAfter.Length, separatorPos - (stringPos + stringToCheckAfter.Length));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static GCodeFile Load(string fileName)
|
||||
{
|
||||
if (FileTooBigToLoad(fileName))
|
||||
{
|
||||
return new GCodeFileStreamed(fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new GCodeFileLoaded(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReplaceNumberAfter(char charToReplaceAfter, string stringWithNumber, double numberToPutIn)
|
||||
{
|
||||
int charPos = stringWithNumber.IndexOf(charToReplaceAfter);
|
||||
if (charPos != -1)
|
||||
{
|
||||
int spacePos = stringWithNumber.IndexOf(" ", charPos);
|
||||
if (spacePos == -1)
|
||||
{
|
||||
string newString = string.Format("{0}{1:0.#####}", stringWithNumber.Substring(0, charPos + 1), numberToPutIn);
|
||||
return newString;
|
||||
}
|
||||
else
|
||||
{
|
||||
string newString = string.Format("{0}{1:0.#####}{2}", stringWithNumber.Substring(0, charPos + 1), numberToPutIn, stringWithNumber.Substring(spacePos));
|
||||
return newString;
|
||||
}
|
||||
}
|
||||
|
||||
return stringWithNumber;
|
||||
}
|
||||
|
||||
protected static double GetSecondsThisLine(Vector3 deltaPositionThisLine, double deltaEPositionThisLine, double feedRateMmPerMin)
|
||||
{
|
||||
double startingVelocityMmPerS = VelocitySameAsStopMmPerS.x;
|
||||
double endingVelocityMmPerS = VelocitySameAsStopMmPerS.x;
|
||||
double maxVelocityMmPerS = Math.Min(feedRateMmPerMin / 60, MaxVelocityMmPerS.x);
|
||||
double acceleration = MaxAccelerationMmPerS2.x;
|
||||
double lengthOfThisMoveMm = Math.Max(deltaPositionThisLine.Length, deltaEPositionThisLine);
|
||||
|
||||
double distanceToMaxVelocity = GetDistanceToReachEndingVelocity(startingVelocityMmPerS, maxVelocityMmPerS, acceleration);
|
||||
if (distanceToMaxVelocity <= lengthOfThisMoveMm / 2)
|
||||
{
|
||||
// we will reach max velocity then run at it and then decelerate
|
||||
double accelerationTime = GetTimeToAccelerateDistance(startingVelocityMmPerS, distanceToMaxVelocity, acceleration) * 2;
|
||||
double runningTime = (lengthOfThisMoveMm - (distanceToMaxVelocity * 2)) / maxVelocityMmPerS;
|
||||
return accelerationTime + runningTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we will accelerate to the center then decelerate
|
||||
double accelerationTime = GetTimeToAccelerateDistance(startingVelocityMmPerS, lengthOfThisMoveMm / 2, acceleration) * 2;
|
||||
return accelerationTime;
|
||||
}
|
||||
}
|
||||
|
||||
private static double GetDistanceToReachEndingVelocity(double startingVelocityMmPerS, double endingVelocityMmPerS, double accelerationMmPerS2)
|
||||
{
|
||||
double endingVelocityMmPerS2 = endingVelocityMmPerS * endingVelocityMmPerS;
|
||||
double startingVelocityMmPerS2 = startingVelocityMmPerS * startingVelocityMmPerS;
|
||||
return (endingVelocityMmPerS2 - startingVelocityMmPerS2) / (2.0 * accelerationMmPerS2);
|
||||
}
|
||||
|
||||
private static double GetTimeToAccelerateDistance(double startingVelocityMmPerS, double distanceMm, double accelerationMmPerS2)
|
||||
{
|
||||
// d = vi * t + .5 * a * t^2;
|
||||
// t = (√(vi^2+2ad)-vi)/a
|
||||
double startingVelocityMmPerS2 = startingVelocityMmPerS * startingVelocityMmPerS;
|
||||
double distanceAcceleration2 = 2 * accelerationMmPerS2 * distanceMm;
|
||||
return (Math.Sqrt(startingVelocityMmPerS2 + distanceAcceleration2) - startingVelocityMmPerS) / accelerationMmPerS2;
|
||||
}
|
||||
|
||||
private static readonly bool Is32Bit = IntPtr.Size == 4;
|
||||
#endregion Static Functions
|
||||
}
|
||||
}
|
||||
969
MatterControl.Printing/GCode/GCodeFileLoaded.cs
Normal file
969
MatterControl.Printing/GCode/GCodeFileLoaded.cs
Normal file
|
|
@ -0,0 +1,969 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
#define MULTI_THREAD
|
||||
#define DUMP_SLOW_TIMES
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public class GCodeFileLoaded : GCodeFile
|
||||
{
|
||||
private double amountOfAccumulatedEWhileParsing = 0;
|
||||
|
||||
private List<int> indexOfChangeInZ = new List<int>();
|
||||
private Vector2 center = Vector2.Zero;
|
||||
private double parsingLastZ;
|
||||
private bool gcodeHasExplicitLayerChangeInfo = false;
|
||||
private double firstLayerThickness;
|
||||
private double layerThickness;
|
||||
|
||||
private double filamentUsedMmCache = 0;
|
||||
private double diameterOfFilamentUsedMmCache = 0;
|
||||
|
||||
private List<PrinterMachineInstruction> GCodeCommandQueue = new List<PrinterMachineInstruction>();
|
||||
|
||||
public GCodeFileLoaded(bool gcodeHasExplicitLayerChangeInfo = false)
|
||||
{
|
||||
this.gcodeHasExplicitLayerChangeInfo = gcodeHasExplicitLayerChangeInfo;
|
||||
}
|
||||
|
||||
public GCodeFileLoaded(string pathAndFileName, bool gcodeHasExplicitLayerChangeInfo = false)
|
||||
{
|
||||
this.gcodeHasExplicitLayerChangeInfo = gcodeHasExplicitLayerChangeInfo;
|
||||
this.Load(pathAndFileName);
|
||||
}
|
||||
|
||||
public override PrinterMachineInstruction Instruction(int index)
|
||||
{
|
||||
return GCodeCommandQueue[index];
|
||||
}
|
||||
|
||||
public override int LineCount => GCodeCommandQueue.Count;
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
indexOfChangeInZ.Clear();
|
||||
GCodeCommandQueue.Clear();
|
||||
}
|
||||
|
||||
public override double TotalSecondsInPrint => Instruction(0).secondsToEndFromHere;
|
||||
|
||||
public void Add(PrinterMachineInstruction printerMachineInstruction)
|
||||
{
|
||||
Insert(LineCount, printerMachineInstruction);
|
||||
}
|
||||
|
||||
public void Insert(int insertIndex, PrinterMachineInstruction printerMachineInstruction)
|
||||
{
|
||||
for (int i = 0; i < indexOfChangeInZ.Count; i++)
|
||||
{
|
||||
if (insertIndex < indexOfChangeInZ[i])
|
||||
{
|
||||
indexOfChangeInZ[i]++;
|
||||
}
|
||||
}
|
||||
|
||||
GCodeCommandQueue.Insert(insertIndex, printerMachineInstruction);
|
||||
}
|
||||
|
||||
public static GCodeFile ParseGCodeString(string gcodeContents)
|
||||
{
|
||||
return ParseFileContents(gcodeContents, null);
|
||||
}
|
||||
|
||||
public static GCodeFileLoaded Load(Stream fileStream)
|
||||
{
|
||||
GCodeFileLoaded loadedGCode = null;
|
||||
try
|
||||
{
|
||||
string gCodeString = "";
|
||||
using (var reader = new StreamReader(fileStream))
|
||||
{
|
||||
gCodeString = reader.ReadToEnd();
|
||||
}
|
||||
|
||||
loadedGCode = ParseFileContents(gCodeString, null);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Debug.Print(e.Message);
|
||||
}
|
||||
|
||||
return loadedGCode;
|
||||
}
|
||||
|
||||
public static async Task<GCodeFileLoaded> LoadInBackground(string fileName, ReportProgressRatio progressReporter)
|
||||
{
|
||||
if (Path.GetExtension(fileName).ToUpper() == ".GCODE")
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(fileName) && !FileTooBigToLoad(fileName))
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
return ParseFileContents(File.ReadAllText(fileName), progressReporter);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Debug.Print(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public new void Load(string gcodePathAndFileName)
|
||||
{
|
||||
if (!FileTooBigToLoad(gcodePathAndFileName))
|
||||
{
|
||||
using (FileStream fileStream = new FileStream(gcodePathAndFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
using (StreamReader streamReader = new StreamReader(fileStream))
|
||||
{
|
||||
GCodeFileLoaded loadedFile = GCodeFileLoaded.Load(streamReader.BaseStream);
|
||||
|
||||
this.indexOfChangeInZ = loadedFile.indexOfChangeInZ;
|
||||
this.center = loadedFile.center;
|
||||
this.parsingLastZ = loadedFile.parsingLastZ;
|
||||
|
||||
this.GCodeCommandQueue = loadedFile.GCodeCommandQueue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> CustomSplit(string newtext, char splitChar)
|
||||
{
|
||||
int endOfLastFind = 0;
|
||||
int positionOfSplitChar = newtext.IndexOf(splitChar);
|
||||
while (positionOfSplitChar != -1)
|
||||
{
|
||||
string text = newtext.Substring(endOfLastFind, positionOfSplitChar - endOfLastFind).Trim();
|
||||
yield return text;
|
||||
endOfLastFind = positionOfSplitChar + 1;
|
||||
positionOfSplitChar = newtext.IndexOf(splitChar, endOfLastFind);
|
||||
}
|
||||
|
||||
string lastText = newtext.Substring(endOfLastFind);
|
||||
yield return lastText;
|
||||
}
|
||||
|
||||
private static int CountNumLines(string gCodeString)
|
||||
{
|
||||
int crCount = 0;
|
||||
foreach (char testCharacter in gCodeString)
|
||||
{
|
||||
if (testCharacter == '\n')
|
||||
{
|
||||
crCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return crCount + 1;
|
||||
}
|
||||
|
||||
public static GCodeFileLoaded ParseFileContents(string gCodeString, ReportProgressRatio progressReporter)
|
||||
{
|
||||
if (gCodeString == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Stopwatch loadTime = Stopwatch.StartNew();
|
||||
|
||||
Stopwatch maxProgressReport = new Stopwatch();
|
||||
maxProgressReport.Start();
|
||||
PrinterMachineInstruction machineInstructionForLine = new PrinterMachineInstruction("None");
|
||||
|
||||
bool gcodeHasExplicitLayerChangeInfo = false;
|
||||
if (gCodeString.Contains("LAYER:"))
|
||||
{
|
||||
gcodeHasExplicitLayerChangeInfo = true;
|
||||
}
|
||||
|
||||
GCodeFileLoaded loadedGCodeFile = new GCodeFileLoaded(gcodeHasExplicitLayerChangeInfo);
|
||||
|
||||
int crCount = CountNumLines(gCodeString);
|
||||
int lineIndex = 0;
|
||||
foreach (string outputString in CustomSplit(gCodeString, '\n'))
|
||||
{
|
||||
string lineString = outputString.Trim();
|
||||
machineInstructionForLine = new PrinterMachineInstruction(lineString, machineInstructionForLine, false);
|
||||
|
||||
if (lineString.Length > 0)
|
||||
{
|
||||
switch (lineString[0])
|
||||
{
|
||||
case 'G':
|
||||
loadedGCodeFile.ParseGLine(lineString, machineInstructionForLine);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
loadedGCodeFile.ParseMLine(lineString, machineInstructionForLine);
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
double extruderIndex = 0;
|
||||
if (GetFirstNumberAfter("T", lineString, ref extruderIndex))
|
||||
{
|
||||
machineInstructionForLine.ExtruderIndex = (int)extruderIndex;
|
||||
}
|
||||
break;
|
||||
|
||||
case ';':
|
||||
if (gcodeHasExplicitLayerChangeInfo && IsLayerChange(lineString))
|
||||
{
|
||||
loadedGCodeFile.IndexOfChangeInZ.Add(loadedGCodeFile.GCodeCommandQueue.Count);
|
||||
}
|
||||
if (lineString.StartsWith("; layerThickness"))
|
||||
{
|
||||
loadedGCodeFile.layerThickness = double.Parse(lineString.Split('=')[1]);
|
||||
}
|
||||
else if (lineString.StartsWith("; firstLayerThickness") && loadedGCodeFile.firstLayerThickness == 0)
|
||||
{
|
||||
loadedGCodeFile.firstLayerThickness = double.Parse(lineString.Split('=')[1]);
|
||||
}
|
||||
break;
|
||||
|
||||
case '@':
|
||||
break;
|
||||
|
||||
default:
|
||||
#if DEBUG
|
||||
throw new NotImplementedException();
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
loadedGCodeFile.GCodeCommandQueue.Add(machineInstructionForLine);
|
||||
|
||||
if (progressReporter != null && maxProgressReport.ElapsedMilliseconds > 200)
|
||||
{
|
||||
progressReporter((double)lineIndex / crCount / 2, "", out bool continueProcessing);
|
||||
if (!continueProcessing)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
maxProgressReport.Restart();
|
||||
}
|
||||
|
||||
lineIndex++;
|
||||
}
|
||||
|
||||
loadedGCodeFile.AnalyzeGCodeLines(progressReporter);
|
||||
|
||||
loadTime.Stop();
|
||||
Console.WriteLine("Time To Load Seconds: {0:0.00}".FormatWith(loadTime.Elapsed.TotalSeconds));
|
||||
|
||||
return loadedGCodeFile;
|
||||
}
|
||||
|
||||
private void AnalyzeGCodeLines(ReportProgressRatio progressReporter)
|
||||
{
|
||||
double feedRateMmPerMin = 0;
|
||||
Vector3 lastPrinterPosition = new Vector3();
|
||||
double lastEPosition = 0;
|
||||
|
||||
Stopwatch maxProgressReport = new Stopwatch();
|
||||
maxProgressReport.Start();
|
||||
|
||||
for (int lineIndex = 0; lineIndex < GCodeCommandQueue.Count; lineIndex++)
|
||||
{
|
||||
PrinterMachineInstruction instruction = GCodeCommandQueue[lineIndex];
|
||||
string line = instruction.Line;
|
||||
Vector3 deltaPositionThisLine = new Vector3();
|
||||
double deltaEPositionThisLine = 0;
|
||||
string lineToParse = line.ToUpper().Trim();
|
||||
if (lineToParse.StartsWith("G0") || lineToParse.StartsWith("G1"))
|
||||
{
|
||||
double newFeedRateMmPerMin = 0;
|
||||
if (GetFirstNumberAfter("F", lineToParse, ref newFeedRateMmPerMin))
|
||||
{
|
||||
feedRateMmPerMin = newFeedRateMmPerMin;
|
||||
}
|
||||
|
||||
Vector3 attemptedDestination = lastPrinterPosition;
|
||||
GetFirstNumberAfter("X", lineToParse, ref attemptedDestination.x);
|
||||
GetFirstNumberAfter("Y", lineToParse, ref attemptedDestination.y);
|
||||
GetFirstNumberAfter("Z", lineToParse, ref attemptedDestination.z);
|
||||
|
||||
double ePosition = lastEPosition;
|
||||
GetFirstNumberAfter("E", lineToParse, ref ePosition);
|
||||
|
||||
deltaPositionThisLine = attemptedDestination - lastPrinterPosition;
|
||||
deltaEPositionThisLine = Math.Abs(ePosition - lastEPosition);
|
||||
|
||||
lastPrinterPosition = attemptedDestination;
|
||||
lastEPosition = ePosition;
|
||||
}
|
||||
else if (lineToParse.StartsWith("G92"))
|
||||
{
|
||||
double ePosition = 0;
|
||||
if (GetFirstNumberAfter("E", lineToParse, ref ePosition))
|
||||
{
|
||||
lastEPosition = ePosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (feedRateMmPerMin > 0)
|
||||
{
|
||||
instruction.secondsThisLine = (float)GetSecondsThisLine(deltaPositionThisLine, deltaEPositionThisLine, feedRateMmPerMin);
|
||||
}
|
||||
|
||||
if (progressReporter != null && maxProgressReport.ElapsedMilliseconds > 200)
|
||||
{
|
||||
progressReporter(((double) lineIndex / GCodeCommandQueue.Count / 2) + .5, "", out bool continueProcessing);
|
||||
if (!continueProcessing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
maxProgressReport.Restart();
|
||||
}
|
||||
}
|
||||
|
||||
double accumulatedTime = 0;
|
||||
for (int i = GCodeCommandQueue.Count - 1; i >= 0; i--)
|
||||
{
|
||||
PrinterMachineInstruction line = GCodeCommandQueue[i];
|
||||
accumulatedTime += line.secondsThisLine;
|
||||
line.secondsToEndFromHere = (float)accumulatedTime;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 Center
|
||||
{
|
||||
get { return center; }
|
||||
}
|
||||
|
||||
public override double PercentComplete(int instructionIndex)
|
||||
{
|
||||
if (GCodeCommandQueue.Count > 0)
|
||||
{
|
||||
return Math.Min(99.9, (double)instructionIndex / (double)GCodeCommandQueue.Count * 100);
|
||||
}
|
||||
|
||||
return 100;
|
||||
}
|
||||
|
||||
public override int GetInstructionIndexAtLayer(int layerIndex)
|
||||
{
|
||||
return IndexOfChangeInZ[layerIndex];
|
||||
}
|
||||
|
||||
private List<int> IndexOfChangeInZ
|
||||
{
|
||||
get { return indexOfChangeInZ; }
|
||||
}
|
||||
|
||||
public override int NumChangesInZ
|
||||
{
|
||||
get { return indexOfChangeInZ.Count; }
|
||||
}
|
||||
|
||||
private void ParseMLine(string lineString, PrinterMachineInstruction processingMachineState)
|
||||
{
|
||||
// take off any comments before we check its length
|
||||
int commentIndex = lineString.IndexOf(';');
|
||||
if (commentIndex != -1)
|
||||
{
|
||||
lineString = lineString.Substring(0, commentIndex);
|
||||
}
|
||||
|
||||
string[] splitOnSpace = lineString.Split(' ');
|
||||
switch (splitOnSpace[0].Substring(1).Trim())
|
||||
{
|
||||
case "01":
|
||||
// show a message?
|
||||
break;
|
||||
|
||||
case "6":
|
||||
// wait for tool to heat up (wait for condition?)
|
||||
break;
|
||||
|
||||
case "101":
|
||||
// extrude on, forward
|
||||
break;
|
||||
|
||||
case "18":
|
||||
// turn off stepers
|
||||
break;
|
||||
|
||||
case "42":
|
||||
// Stop on material exhausted / Switch I/O pin
|
||||
break;
|
||||
|
||||
case "72":
|
||||
// makerbot, Play tone or song
|
||||
break;
|
||||
|
||||
case "73":
|
||||
// makerbot, Manually set build percentage
|
||||
break;
|
||||
|
||||
case "82":
|
||||
// set extruder to absolute mode
|
||||
break;
|
||||
|
||||
case "83":
|
||||
//Set extruder to relative mode
|
||||
break;
|
||||
|
||||
case "84":
|
||||
// lineString = "M84 ; disable motors\r"
|
||||
break;
|
||||
|
||||
case "92":
|
||||
// set steps per mm
|
||||
break;
|
||||
|
||||
case "102":
|
||||
// extrude on reverse
|
||||
break;
|
||||
|
||||
case "103":
|
||||
// extrude off
|
||||
break;
|
||||
|
||||
case "104":
|
||||
// set extruder tempreature
|
||||
break;
|
||||
|
||||
case "105":
|
||||
// M105 Custom code for temperature reading. (Not used)
|
||||
break;
|
||||
|
||||
case "106":
|
||||
// turn fan on
|
||||
break;
|
||||
|
||||
case "107":
|
||||
// turn fan off
|
||||
break;
|
||||
|
||||
case "108":
|
||||
// set extruder speed
|
||||
break;
|
||||
|
||||
case "109":
|
||||
// set heated platform temperature
|
||||
break;
|
||||
|
||||
case "114":
|
||||
break;
|
||||
|
||||
case "117":
|
||||
// in Marlin: Display Message
|
||||
break;
|
||||
|
||||
case "126":
|
||||
// enable fan (makerbot)
|
||||
break;
|
||||
|
||||
case "127":
|
||||
// disable fan (makerbot)
|
||||
break;
|
||||
|
||||
case "132":
|
||||
// recall stored home offsets for axis xyzab
|
||||
break;
|
||||
|
||||
case "133":
|
||||
// MakerBot wait for toolhead to heat
|
||||
break;
|
||||
|
||||
case "134":
|
||||
// MakerBot wait for platform to reach target temp
|
||||
break;
|
||||
|
||||
case "135":
|
||||
// MakerBot change toolhead
|
||||
break;
|
||||
|
||||
case "140":
|
||||
// set bed temperature
|
||||
break;
|
||||
|
||||
case "190":
|
||||
// wait for bed temperature to be reached
|
||||
break;
|
||||
|
||||
case "200":
|
||||
// M200 sets the filament diameter.
|
||||
break;
|
||||
|
||||
case "201":
|
||||
// set axis acceleration
|
||||
break;
|
||||
|
||||
case "204": // - Set default acceleration
|
||||
break;
|
||||
|
||||
case "207": // M207: calibrate z axis by detecting z max length
|
||||
break;
|
||||
|
||||
case "208": // M208: set axis max travel
|
||||
break;
|
||||
|
||||
case "209": // M209: enable automatic retract
|
||||
break;
|
||||
|
||||
case "210": // Set homing rate
|
||||
break;
|
||||
|
||||
case "226": // user request pause
|
||||
break;
|
||||
|
||||
case "227": // Enable Automatic Reverse and Prime
|
||||
break;
|
||||
|
||||
case "301":
|
||||
break;
|
||||
|
||||
case "400": // Wait for current moves to finish
|
||||
break;
|
||||
|
||||
case "565": // M565: Set Z probe offset
|
||||
break;
|
||||
case "1200"://M1200 Makerbot Fake gCode command for start build notification
|
||||
break;
|
||||
case "1201"://M1201 Makerbot Fake gCode command for end build notification
|
||||
break;
|
||||
case "1202"://M1202 Makerbot Fake gCode command for reset board
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseGLine(string lineString, PrinterMachineInstruction processingMachineState)
|
||||
{
|
||||
// take off any comments before we check its length
|
||||
int commentIndex = lineString.IndexOf(';');
|
||||
if (commentIndex != -1)
|
||||
{
|
||||
lineString = lineString.Substring(0, commentIndex);
|
||||
}
|
||||
|
||||
string[] splitOnSpace = lineString.Split(' ');
|
||||
string onlyNumber = splitOnSpace[0].Substring(1).Trim();
|
||||
switch (onlyNumber)
|
||||
{
|
||||
case "0":
|
||||
goto case "1";
|
||||
|
||||
case "4":
|
||||
case "04":
|
||||
// wait a given number of miliseconds
|
||||
break;
|
||||
|
||||
case "1":
|
||||
// get the x y z to move to
|
||||
{
|
||||
double valueX = 0;
|
||||
if (GCodeFile.GetFirstNumberAfter("X", lineString, ref valueX))
|
||||
{
|
||||
processingMachineState.X = valueX;
|
||||
}
|
||||
double valueY = 0;
|
||||
if (GCodeFile.GetFirstNumberAfter("Y", lineString, ref valueY))
|
||||
{
|
||||
processingMachineState.Y = valueY;
|
||||
}
|
||||
double valueZ = 0;
|
||||
if (GCodeFile.GetFirstNumberAfter("Z", lineString, ref valueZ))
|
||||
{
|
||||
processingMachineState.Z = valueZ;
|
||||
}
|
||||
double valueE = 0;
|
||||
if (GCodeFile.GetFirstNumberAfter("E", lineString, ref valueE))
|
||||
{
|
||||
if (processingMachineState.movementType == PrinterMachineInstruction.MovementTypes.Absolute)
|
||||
{
|
||||
processingMachineState.EPosition = valueE + amountOfAccumulatedEWhileParsing;
|
||||
}
|
||||
else
|
||||
{
|
||||
processingMachineState.EPosition += valueE;
|
||||
}
|
||||
}
|
||||
double valueF = 0;
|
||||
if (GCodeFile.GetFirstNumberAfter("F", lineString, ref valueF))
|
||||
{
|
||||
processingMachineState.FeedRate = valueF;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gcodeHasExplicitLayerChangeInfo)
|
||||
{
|
||||
if (processingMachineState.Z != parsingLastZ || indexOfChangeInZ.Count == 0)
|
||||
{
|
||||
// if we changed z or there is a movement and we have never started a layer index
|
||||
indexOfChangeInZ.Add(GCodeCommandQueue.Count);
|
||||
}
|
||||
}
|
||||
parsingLastZ = processingMachineState.Position.z;
|
||||
break;
|
||||
|
||||
case "10": // firmware retract
|
||||
break;
|
||||
|
||||
case "11": // firmware unretract
|
||||
break;
|
||||
|
||||
case "21":
|
||||
// set to metric
|
||||
break;
|
||||
|
||||
case "28":
|
||||
// G28 Return to home position (machine zero, aka machine reference point)
|
||||
break;
|
||||
|
||||
case "29":
|
||||
// G29 Probe the z-bed in 3 places
|
||||
break;
|
||||
|
||||
case "30":
|
||||
// G30 Probe z in current position
|
||||
break;
|
||||
|
||||
case "90": // G90 is Absolute Distance Mode
|
||||
processingMachineState.movementType = PrinterMachineInstruction.MovementTypes.Absolute;
|
||||
break;
|
||||
|
||||
case "91": // G91 is Incremental Distance Mode
|
||||
processingMachineState.movementType = PrinterMachineInstruction.MovementTypes.Relative;
|
||||
break;
|
||||
|
||||
case "92":
|
||||
// set current head position values (used to reset origin)
|
||||
double ePosition = 0;
|
||||
if (GetFirstNumberAfter("E", lineString, ref ePosition))
|
||||
{
|
||||
// remember how much e position we just gave up
|
||||
amountOfAccumulatedEWhileParsing = (processingMachineState.EPosition - ePosition);
|
||||
}
|
||||
break;
|
||||
|
||||
case "130":
|
||||
//Set Digital Potentiometer value
|
||||
break;
|
||||
|
||||
case "161":
|
||||
// home x,y axis minimum
|
||||
break;
|
||||
|
||||
case "162":
|
||||
// home z axis maximum
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override Vector2 GetWeightedCenter()
|
||||
{
|
||||
Vector2 total = new Vector2();
|
||||
#if !MULTI_THREAD
|
||||
foreach (PrinterMachineInstruction state in GCodeCommandQueue)
|
||||
{
|
||||
total += new Vector2(state.Position.x, state.Position.y);
|
||||
}
|
||||
#else
|
||||
Parallel.For<Vector2>(
|
||||
0,
|
||||
GCodeCommandQueue.Count,
|
||||
() => new Vector2(),
|
||||
(int index, ParallelLoopState loop, Vector2 subtotal) =>
|
||||
{
|
||||
PrinterMachineInstruction state = GCodeCommandQueue[index];
|
||||
subtotal += new Vector2(state.Position.x, state.Position.y);
|
||||
return subtotal;
|
||||
},
|
||||
(x) =>
|
||||
{
|
||||
total += new Vector2(x.x, x.y);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
return total / GCodeCommandQueue.Count;
|
||||
}
|
||||
|
||||
public override RectangleDouble GetBounds()
|
||||
{
|
||||
RectangleDouble bounds = new RectangleDouble(double.MaxValue, double.MaxValue, double.MinValue, double.MinValue);
|
||||
#if !MULTI_THREAD
|
||||
foreach (PrinterMachineInstruction state in GCodeCommandQueue)
|
||||
{
|
||||
bounds.Left = Math.Min(state.Position.x, bounds.Left);
|
||||
bounds.Right = Math.Max(state.Position.x, bounds.Right);
|
||||
bounds.Bottom = Math.Min(state.Position.y, bounds.Bottom);
|
||||
bounds.Top = Math.Max(state.Position.y, bounds.Top);
|
||||
}
|
||||
#else
|
||||
Parallel.For<RectangleDouble>(
|
||||
0,
|
||||
GCodeCommandQueue.Count,
|
||||
() => new RectangleDouble(double.MaxValue, double.MaxValue, double.MinValue, double.MinValue),
|
||||
(int index, ParallelLoopState loop, RectangleDouble subtotal) =>
|
||||
{
|
||||
PrinterMachineInstruction state = GCodeCommandQueue[index];
|
||||
subtotal.Left = Math.Min(state.Position.x, subtotal.Left);
|
||||
subtotal.Right = Math.Max(state.Position.x, subtotal.Right);
|
||||
subtotal.Bottom = Math.Min(state.Position.y, subtotal.Bottom);
|
||||
subtotal.Top = Math.Max(state.Position.y, subtotal.Top);
|
||||
|
||||
return subtotal;
|
||||
},
|
||||
(x) =>
|
||||
{
|
||||
bounds.Left = Math.Min(x.Left, bounds.Left);
|
||||
bounds.Right = Math.Max(x.Right, bounds.Right);
|
||||
bounds.Bottom = Math.Min(x.Bottom, bounds.Bottom);
|
||||
bounds.Top = Math.Max(x.Top, bounds.Top);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public override bool IsExtruding(int instructionIndexToCheck)
|
||||
{
|
||||
if (instructionIndexToCheck > 1 && instructionIndexToCheck < GCodeCommandQueue.Count)
|
||||
{
|
||||
double extrusionLengeth = GCodeCommandQueue[instructionIndexToCheck].EPosition - GCodeCommandQueue[instructionIndexToCheck - 1].EPosition;
|
||||
if (extrusionLengeth > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override double GetFilamentUsedMm(double filamentDiameter)
|
||||
{
|
||||
if (filamentUsedMmCache == 0 || filamentDiameter != diameterOfFilamentUsedMmCache)
|
||||
{
|
||||
double lastEPosition = 0;
|
||||
double filamentMm = 0;
|
||||
for (int i = 0; i < GCodeCommandQueue.Count; i++)
|
||||
{
|
||||
PrinterMachineInstruction instruction = GCodeCommandQueue[i];
|
||||
//filamentMm += instruction.EPosition;
|
||||
|
||||
string lineToParse = instruction.Line;
|
||||
if (lineToParse.StartsWith("G0") || lineToParse.StartsWith("G1"))
|
||||
{
|
||||
double ePosition = lastEPosition;
|
||||
if (GetFirstNumberAfter("E", lineToParse, ref ePosition))
|
||||
{
|
||||
if (instruction.movementType == PrinterMachineInstruction.MovementTypes.Absolute)
|
||||
{
|
||||
double deltaEPosition = ePosition - lastEPosition;
|
||||
filamentMm += deltaEPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
filamentMm += ePosition;
|
||||
}
|
||||
|
||||
lastEPosition = ePosition;
|
||||
}
|
||||
}
|
||||
else if (lineToParse.StartsWith("G92"))
|
||||
{
|
||||
double ePosition = 0;
|
||||
if (GetFirstNumberAfter("E", lineToParse, ref ePosition))
|
||||
{
|
||||
lastEPosition = ePosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filamentUsedMmCache = filamentMm;
|
||||
diameterOfFilamentUsedMmCache = filamentDiameter;
|
||||
}
|
||||
|
||||
return filamentUsedMmCache;
|
||||
}
|
||||
|
||||
public override double GetFilamentCubicMm(double filamentDiameterMm)
|
||||
{
|
||||
double filamentUsedMm = GetFilamentUsedMm(filamentDiameterMm);
|
||||
double filamentRadius = filamentDiameterMm / 2;
|
||||
double areaSquareMm = (filamentRadius * filamentRadius) * Math.PI;
|
||||
|
||||
return areaSquareMm * filamentUsedMm;
|
||||
}
|
||||
|
||||
public override double GetFilamentWeightGrams(double filamentDiameterMm, double densityGramsPerCubicCm)
|
||||
{
|
||||
double cubicMmPerCubicCm = 1000;
|
||||
double gramsPerCubicMm = densityGramsPerCubicCm / cubicMmPerCubicCm;
|
||||
double cubicMms = GetFilamentCubicMm(filamentDiameterMm);
|
||||
return cubicMms * gramsPerCubicMm;
|
||||
}
|
||||
|
||||
public void Save(string dest)
|
||||
{
|
||||
using (StreamWriter file = new StreamWriter(dest))
|
||||
{
|
||||
foreach (PrinterMachineInstruction instruction in GCodeCommandQueue)
|
||||
{
|
||||
file.WriteLine(instruction.Line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double filamentDiameterCache = 0;
|
||||
public override double GetFilamentDiameter()
|
||||
{
|
||||
if (filamentDiameterCache == 0)
|
||||
{
|
||||
for (int i = 0; i < Math.Min(20, GCodeCommandQueue.Count); i++)
|
||||
{
|
||||
if (GetFirstNumberAfter("filamentDiameter =", GCodeCommandQueue[i].Line, ref filamentDiameterCache))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (filamentDiameterCache == 0)
|
||||
{
|
||||
// didn't find it, so look at the end of the file for filament_diameter =
|
||||
string lookFor = "; filament_diameter =";// 2.85
|
||||
for (int i = GCodeCommandQueue.Count - 1; i > Math.Max(0, GCodeCommandQueue.Count - 100); i--)
|
||||
{
|
||||
if (GetFirstNumberAfter(lookFor, GCodeCommandQueue[i].Line, ref filamentDiameterCache))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(filamentDiameterCache == 0)
|
||||
{
|
||||
// it is still 0 so set it to something so we render
|
||||
filamentDiameterCache = 1.75;
|
||||
}
|
||||
}
|
||||
|
||||
return filamentDiameterCache;
|
||||
}
|
||||
|
||||
public override double GetLayerHeight()
|
||||
{
|
||||
if (layerThickness > 0)
|
||||
{
|
||||
return layerThickness;
|
||||
}
|
||||
|
||||
if (indexOfChangeInZ.Count > 2)
|
||||
{
|
||||
return GCodeCommandQueue[IndexOfChangeInZ[2]].Z - GCodeCommandQueue[IndexOfChangeInZ[1]].Z;
|
||||
}
|
||||
|
||||
return .5;
|
||||
}
|
||||
|
||||
public override double GetFirstLayerHeight()
|
||||
{
|
||||
if (firstLayerThickness > 0)
|
||||
{
|
||||
return firstLayerThickness;
|
||||
}
|
||||
|
||||
if (indexOfChangeInZ.Count > 1)
|
||||
{
|
||||
return GCodeCommandQueue[IndexOfChangeInZ[1]].Z - GCodeCommandQueue[IndexOfChangeInZ[0]].Z;
|
||||
}
|
||||
|
||||
return .5;
|
||||
}
|
||||
|
||||
public override int GetLayerIndex(int instructionIndex)
|
||||
{
|
||||
if (instructionIndex >= 0
|
||||
&& instructionIndex < LineCount)
|
||||
{
|
||||
for (int zIndex = 0; zIndex < NumChangesInZ; zIndex++)
|
||||
{
|
||||
if (instructionIndex < IndexOfChangeInZ[zIndex])
|
||||
{
|
||||
return zIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return NumChangesInZ - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public override double Ratio0to1IntoContainedLayer(int instructionIndex)
|
||||
{
|
||||
int currentLayer = GetLayerIndex(instructionIndex);
|
||||
|
||||
if (currentLayer > -1)
|
||||
{
|
||||
int startIndex = 0;
|
||||
if (currentLayer > 0)
|
||||
{
|
||||
startIndex = IndexOfChangeInZ[currentLayer - 1];
|
||||
}
|
||||
int endIndex = LineCount - 1;
|
||||
if (currentLayer < NumChangesInZ - 1)
|
||||
{
|
||||
endIndex = IndexOfChangeInZ[currentLayer];
|
||||
}
|
||||
|
||||
int deltaFromStart = Math.Max(0, instructionIndex - startIndex);
|
||||
return deltaFromStart / (double)(endIndex - startIndex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
286
MatterControl.Printing/GCode/GCodeFileStreamed.cs
Normal file
286
MatterControl.Printing/GCode/GCodeFileStreamed.cs
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
#define MULTI_THREAD
|
||||
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.VectorMath;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public class GCodeFileStreamed : GCodeFile
|
||||
{
|
||||
private StreamReader openGcodeStream;
|
||||
object locker = new object();
|
||||
|
||||
private bool readLastLineOfFile = false;
|
||||
private int readLineCount = 0;
|
||||
private const int MaxLinesToBuffer = 128;
|
||||
private PrinterMachineInstruction[] readLinesRingBuffer = new PrinterMachineInstruction[MaxLinesToBuffer];
|
||||
|
||||
public GCodeFileStreamed(string fileName)
|
||||
{
|
||||
var inStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
openGcodeStream = new StreamReader(inStream);
|
||||
}
|
||||
|
||||
~GCodeFileStreamed()
|
||||
{
|
||||
CloseStream();
|
||||
}
|
||||
|
||||
private void CloseStream()
|
||||
{
|
||||
if (openGcodeStream != null)
|
||||
{
|
||||
openGcodeStream.Close();
|
||||
openGcodeStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override int LineCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (openGcodeStream != null
|
||||
&& !readLastLineOfFile)
|
||||
{
|
||||
return Math.Max(readLineCount + 1, (int)(openGcodeStream.BaseStream.Length / 14));
|
||||
}
|
||||
|
||||
return readLineCount;
|
||||
}
|
||||
}
|
||||
|
||||
public long ByteCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (openGcodeStream != null
|
||||
&& !readLastLineOfFile)
|
||||
{
|
||||
return openGcodeStream.BaseStream.Length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public long BytePosition
|
||||
{
|
||||
get
|
||||
{
|
||||
if (openGcodeStream != null
|
||||
&& !readLastLineOfFile)
|
||||
{
|
||||
return openGcodeStream.BaseStream.Position;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public override double TotalSecondsInPrint
|
||||
{
|
||||
get
|
||||
{
|
||||
// We don't know, so we always return -1 used to identify as streaming.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
CloseStream();
|
||||
|
||||
readLastLineOfFile = false;
|
||||
readLineCount = 0;
|
||||
}
|
||||
|
||||
public override Vector2 GetWeightedCenter()
|
||||
{
|
||||
throw new NotImplementedException("A streamed GCode file should not need to do this. Please validate the code that is calling this.");
|
||||
}
|
||||
|
||||
public override RectangleDouble GetBounds()
|
||||
{
|
||||
throw new NotImplementedException("A streamed GCode file should not need to do this. Please validate the code that is calling this.");
|
||||
}
|
||||
|
||||
public override double GetFilamentCubicMm(double filamentDiameter)
|
||||
{
|
||||
throw new NotImplementedException("A streamed GCode file should not need to do this. Please validate the code that is calling this.");
|
||||
}
|
||||
|
||||
public override bool IsExtruding(int instructionIndexToCheck)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override double GetLayerHeight()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override double GetFirstLayerHeight()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override double GetFilamentUsedMm(double filamentDiameter)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override double PercentComplete(int instructionIndex)
|
||||
{
|
||||
lock(locker)
|
||||
{
|
||||
if (openGcodeStream != null
|
||||
&& openGcodeStream.BaseStream.Length > 0)
|
||||
{
|
||||
return (double)openGcodeStream.BaseStream.Position / (double)openGcodeStream.BaseStream.Length * 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
return 100;
|
||||
}
|
||||
|
||||
public override int GetInstructionIndexAtLayer(int layerIndex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override double GetFilamentDiameter()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override double GetFilamentWeightGrams(double filamentDiameterMm, double density)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override int GetLayerIndex(int instructionIndex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override int NumChangesInZ
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private double feedRateMmPerMin = 0;
|
||||
private Vector3 lastPrinterPosition = new Vector3();
|
||||
private double lastEPosition = 0;
|
||||
|
||||
public override PrinterMachineInstruction Instruction(int index)
|
||||
{
|
||||
lock(locker)
|
||||
{
|
||||
if (index < readLineCount - MaxLinesToBuffer)
|
||||
{
|
||||
throw new Exception("You are asking for a line we no longer have buffered");
|
||||
}
|
||||
|
||||
while (index >= readLineCount)
|
||||
{
|
||||
string line = openGcodeStream.ReadLine();
|
||||
if (line == null)
|
||||
{
|
||||
readLastLineOfFile = true;
|
||||
line = "";
|
||||
}
|
||||
|
||||
int ringBufferIndex = readLineCount % MaxLinesToBuffer;
|
||||
readLinesRingBuffer[ringBufferIndex] = new PrinterMachineInstruction(line);
|
||||
|
||||
PrinterMachineInstruction instruction = readLinesRingBuffer[ringBufferIndex];
|
||||
Vector3 deltaPositionThisLine = new Vector3();
|
||||
double deltaEPositionThisLine = 0;
|
||||
string lineToParse = line.ToUpper().Trim();
|
||||
if (lineToParse.StartsWith("G0") || lineToParse.StartsWith("G1"))
|
||||
{
|
||||
double newFeedRateMmPerMin = 0;
|
||||
if (GetFirstNumberAfter("F", lineToParse, ref newFeedRateMmPerMin))
|
||||
{
|
||||
feedRateMmPerMin = newFeedRateMmPerMin;
|
||||
}
|
||||
|
||||
Vector3 attemptedDestination = lastPrinterPosition;
|
||||
GetFirstNumberAfter("X", lineToParse, ref attemptedDestination.x);
|
||||
GetFirstNumberAfter("Y", lineToParse, ref attemptedDestination.y);
|
||||
GetFirstNumberAfter("Z", lineToParse, ref attemptedDestination.z);
|
||||
|
||||
double ePosition = lastEPosition;
|
||||
GetFirstNumberAfter("E", lineToParse, ref ePosition);
|
||||
|
||||
deltaPositionThisLine = attemptedDestination - lastPrinterPosition;
|
||||
deltaEPositionThisLine = Math.Abs(ePosition - lastEPosition);
|
||||
|
||||
lastPrinterPosition = attemptedDestination;
|
||||
lastEPosition = ePosition;
|
||||
}
|
||||
else if (lineToParse.StartsWith("G92"))
|
||||
{
|
||||
double ePosition = 0;
|
||||
if (GetFirstNumberAfter("E", lineToParse, ref ePosition))
|
||||
{
|
||||
lastEPosition = ePosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (feedRateMmPerMin > 0)
|
||||
{
|
||||
instruction.secondsThisLine = (float)GetSecondsThisLine(deltaPositionThisLine, deltaEPositionThisLine, feedRateMmPerMin);
|
||||
}
|
||||
|
||||
readLineCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return readLinesRingBuffer[index % MaxLinesToBuffer];
|
||||
}
|
||||
|
||||
public override double Ratio0to1IntoContainedLayer(int instructionIndex)
|
||||
{
|
||||
if (ByteCount != 0)
|
||||
{
|
||||
return BytePosition / (double)ByteCount;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
152
MatterControl.Printing/GCode/PrinterMachineInstruction.cs
Normal file
152
MatterControl.Printing/GCode/PrinterMachineInstruction.cs
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using MatterHackers.VectorMath;
|
||||
using System.Text;
|
||||
|
||||
namespace MatterHackers.GCodeVisualizer
|
||||
{
|
||||
public class PrinterMachineInstruction
|
||||
{
|
||||
public byte[] byteLine;
|
||||
|
||||
public string Line
|
||||
{
|
||||
get
|
||||
{
|
||||
return Encoding.Default.GetString(byteLine);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
byteLine = Encoding.Default.GetBytes(value);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3Float xyzPosition = new Vector3Float();
|
||||
private float ePosition = 0;
|
||||
private float feedRate = 0;
|
||||
|
||||
public enum MovementTypes { Absolute, Relative };
|
||||
|
||||
// Absolute is the RepRap default
|
||||
public MovementTypes movementType = MovementTypes.Absolute;
|
||||
|
||||
public float secondsThisLine;
|
||||
public float secondsToEndFromHere;
|
||||
public bool clientInsertion;
|
||||
|
||||
public PrinterMachineInstruction(string Line)
|
||||
{
|
||||
this.Line = Line;
|
||||
}
|
||||
|
||||
public PrinterMachineInstruction(string Line, PrinterMachineInstruction copy, bool clientInsertion = false)
|
||||
: this(Line)
|
||||
{
|
||||
xyzPosition = copy.xyzPosition;
|
||||
feedRate = copy.feedRate;
|
||||
ePosition = copy.ePosition;
|
||||
movementType = copy.movementType;
|
||||
secondsToEndFromHere = copy.secondsToEndFromHere;
|
||||
ExtruderIndex = copy.ExtruderIndex;
|
||||
this.clientInsertion = clientInsertion;
|
||||
}
|
||||
|
||||
public int ExtruderIndex { get; set; }
|
||||
|
||||
public Vector3 Position
|
||||
{
|
||||
get { return new Vector3(xyzPosition); }
|
||||
}
|
||||
|
||||
public double X
|
||||
{
|
||||
get { return xyzPosition.x; }
|
||||
set
|
||||
{
|
||||
if (movementType == MovementTypes.Absolute)
|
||||
{
|
||||
xyzPosition.x = (float)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
xyzPosition.x += (float)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double Y
|
||||
{
|
||||
get { return xyzPosition.y; }
|
||||
set
|
||||
{
|
||||
if (movementType == MovementTypes.Absolute)
|
||||
{
|
||||
xyzPosition.y = (float)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
xyzPosition.y += (float)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double Z
|
||||
{
|
||||
get { return xyzPosition.z; }
|
||||
set
|
||||
{
|
||||
if (movementType == MovementTypes.Absolute)
|
||||
{
|
||||
xyzPosition.z = (float)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
xyzPosition.z += (float)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double EPosition
|
||||
{
|
||||
get { return ePosition; }
|
||||
set
|
||||
{
|
||||
ePosition = (float)value;
|
||||
}
|
||||
}
|
||||
|
||||
public double FeedRate
|
||||
{
|
||||
get { return feedRate; }
|
||||
set { feedRate = (float)value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
61
MatterControl.Printing/MatterControl.Printing.csproj
Normal file
61
MatterControl.Printing/MatterControl.Printing.csproj
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{97D5ADE3-C1B4-4B46-8A3E-718A4F7F079F}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MatterControl.Printing</RootNamespace>
|
||||
<AssemblyName>MatterControl.Printing</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="GCode\GCodeFile.cs" />
|
||||
<Compile Include="GCode\GCodeFileLoaded.cs" />
|
||||
<Compile Include="GCode\GCodeFileStreamed.cs" />
|
||||
<Compile Include="GCode\PrinterMachineInstruction.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\agg\Agg.csproj">
|
||||
<Project>{657dbc6d-c3ea-4398-a3fa-ddb73c14f71b}</Project>
|
||||
<Name>Agg</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\VectorMath\VectorMath.csproj">
|
||||
<Project>{d3e41b4e-bfbb-44ca-94c8-95c00f754fdd}</Project>
|
||||
<Name>VectorMath</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
36
MatterControl.Printing/Properties/AssemblyInfo.cs
Normal file
36
MatterControl.Printing/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MatterControl.Printing")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MatterControl.Printing")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("97d5ade3-c1b4-4b46-8a3e-718a4f7f079f")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
|
@ -209,6 +209,9 @@
|
|||
<Compile Include="Library\Providers\Zip\ZipMemoryContainer.cs" />
|
||||
<Compile Include="PartPreviewWindow\OverflowDropdown.cs" />
|
||||
<Compile Include="PartPreviewWindow\View3D\GridOptionsPanel.cs" />
|
||||
<Compile Include="PartPreviewWindow\View3D\InteractionVolume.cs" />
|
||||
<Compile Include="PartPreviewWindow\View3D\MeshViewerWidget.cs" />
|
||||
<Compile Include="PartPreviewWindow\View3D\MouseEvent3DArgs.cs" />
|
||||
<Compile Include="PartPreviewWindow\View3D\PrinterActionsBar.cs" />
|
||||
<Compile Include="PrinterCommunication\Io\NotPrintingStream.cs" />
|
||||
<Compile Include="Library\Widgets\ListView\ListView.cs" />
|
||||
|
|
@ -474,6 +477,14 @@
|
|||
<Folder Include="SlicerConfiguration\SettingsEditors\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="MatterControl.OpenGL\MatterControl.OpenGL.csproj">
|
||||
<Project>{CBDEEC31-D688-417B-9BF2-F0DB2E4FB268}</Project>
|
||||
<Name>MatterControl.OpenGL</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="MatterControl.Printing\MatterControl.Printing.csproj">
|
||||
<Project>{97D5ADE3-C1B4-4B46-8A3E-718A4F7F079F}</Project>
|
||||
<Name>MatterControl.Printing</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="Submodules\agg-sharp\clipper_library\clipper_library.csproj">
|
||||
<Project>{9B062971-A88E-4A3D-B3C9-12B78D15FA66}</Project>
|
||||
<Name>clipper_library</Name>
|
||||
|
|
@ -518,10 +529,6 @@
|
|||
<Project>{D3E41B4E-BFBB-44CA-94C8-95C00F754FDD}</Project>
|
||||
<Name>VectorMath</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="Submodules\agg-sharp\examples\GCodeVisualizer\GCodeVisualizer.csproj">
|
||||
<Project>{F67AE800-B0C7-42A8-836F-597B4E74591C}</Project>
|
||||
<Name>GCodeVisualizer</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="Submodules\agg-sharp\SerialPortCommunication\SerialPortCommunication.csproj">
|
||||
<Project>{D3ABF72C-64C2-4E51-A119-E077210FA990}</Project>
|
||||
<Name>SerialPortCommunication</Name>
|
||||
|
|
@ -534,10 +541,6 @@
|
|||
<Project>{C46CA728-DD2F-4DD1-971A-AAA89D9DFF95}</Project>
|
||||
<Name>MatterSlice</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="Submodules\agg-sharp\examples\MeshViewer\MeshViewer.csproj">
|
||||
<Project>{A737BC76-165B-46C6-82B7-8871C7C92942}</Project>
|
||||
<Name>MeshViewer</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="Submodules\agg-sharp\Tesselate\Tesselate.csproj">
|
||||
<Project>{AE37DE1F-22F7-49EE-8732-FC6BC8DC58D9}</Project>
|
||||
<Name>Tesselate</Name>
|
||||
|
|
|
|||
206
PartPreviewWindow/View3D/InteractionVolume.cs
Normal file
206
PartPreviewWindow/View3D/InteractionVolume.cs
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Font;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.Transform;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.RayTracer;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MeshVisualizer
|
||||
{
|
||||
[Flags]
|
||||
public enum LineArrows { None = 0, Start = 1, End = 2, Both = 3 };
|
||||
|
||||
public class InteractionVolume
|
||||
{
|
||||
public bool MouseDownOnControl;
|
||||
public Matrix4X4 TotalTransform = Matrix4X4.Identity;
|
||||
|
||||
private bool mouseOver = false;
|
||||
|
||||
public InteractionVolume(IPrimitive collisionVolume, MeshViewerWidget meshViewerToDrawWith)
|
||||
{
|
||||
this.CollisionVolume = collisionVolume;
|
||||
this.MeshViewerToDrawWith = meshViewerToDrawWith;
|
||||
}
|
||||
|
||||
public IPrimitive CollisionVolume { get; set; }
|
||||
|
||||
public bool DrawOnTop { get; protected set; }
|
||||
|
||||
protected MeshViewerWidget MeshViewerToDrawWith { get; }
|
||||
|
||||
public IntersectInfo MouseMoveInfo { get; set; }
|
||||
|
||||
public bool MouseOver
|
||||
{
|
||||
get
|
||||
{
|
||||
return mouseOver;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (mouseOver != value)
|
||||
{
|
||||
mouseOver = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3 SetBottomControlHeight(AxisAlignedBoundingBox originalSelectedBounds, Vector3 cornerPosition)
|
||||
{
|
||||
if (originalSelectedBounds.minXYZ.z < 0)
|
||||
{
|
||||
if (originalSelectedBounds.maxXYZ.z < 0)
|
||||
{
|
||||
cornerPosition.z = originalSelectedBounds.maxXYZ.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
cornerPosition.z = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return cornerPosition;
|
||||
}
|
||||
|
||||
public static void DrawMeasureLine(Graphics2D graphics2D, Vector2 lineStart, Vector2 lineEnd, RGBA_Bytes color, LineArrows arrows)
|
||||
{
|
||||
graphics2D.Line(lineStart, lineEnd, RGBA_Bytes.Black);
|
||||
|
||||
Vector2 direction = lineEnd - lineStart;
|
||||
if (direction.LengthSquared > 0
|
||||
&& (arrows.HasFlag(LineArrows.Start) || arrows.HasFlag(LineArrows.End)))
|
||||
{
|
||||
PathStorage arrow = new PathStorage();
|
||||
arrow.MoveTo(-3, -5);
|
||||
arrow.LineTo(0, 0);
|
||||
arrow.LineTo(3, -5);
|
||||
if (arrows.HasFlag(LineArrows.End))
|
||||
{
|
||||
double rotation = Math.Atan2(direction.y, direction.x);
|
||||
IVertexSource correctRotation = new VertexSourceApplyTransform(arrow, Affine.NewRotation(rotation - MathHelper.Tau / 4));
|
||||
IVertexSource inPosition = new VertexSourceApplyTransform(correctRotation, Affine.NewTranslation(lineEnd));
|
||||
graphics2D.Render(inPosition, RGBA_Bytes.Black);
|
||||
}
|
||||
if (arrows.HasFlag(LineArrows.Start))
|
||||
{
|
||||
double rotation = Math.Atan2(direction.y, direction.x) + MathHelper.Tau / 2;
|
||||
IVertexSource correctRotation = new VertexSourceApplyTransform(arrow, Affine.NewRotation(rotation - MathHelper.Tau / 4));
|
||||
IVertexSource inPosition = new VertexSourceApplyTransform(correctRotation, Affine.NewTranslation(lineStart));
|
||||
graphics2D.Render(inPosition, RGBA_Bytes.Black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Draw2DContent(Agg.Graphics2D graphics2D)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void DrawGlContent(EventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
MeshViewerToDrawWith.Invalidate();
|
||||
}
|
||||
|
||||
public virtual void OnMouseDown(MouseEvent3DArgs mouseEvent3D)
|
||||
{
|
||||
MouseDownOnControl = true;
|
||||
MeshViewerToDrawWith.Invalidate();
|
||||
}
|
||||
|
||||
public virtual void OnMouseMove(MouseEvent3DArgs mouseEvent3D)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnMouseUp(MouseEvent3DArgs mouseEvent3D)
|
||||
{
|
||||
MouseDownOnControl = false;
|
||||
}
|
||||
|
||||
public virtual void SetPosition(IObject3D selectedItem)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ValueDisplayInfo
|
||||
{
|
||||
private string formatString;
|
||||
private string measureDisplayedString = "";
|
||||
private ImageBuffer measureDisplayImage = null;
|
||||
private string unitsString;
|
||||
|
||||
public ValueDisplayInfo(string formatString = "{0:0.00}", string unitsString = "mm")
|
||||
{
|
||||
this.formatString = formatString;
|
||||
this.unitsString = unitsString;
|
||||
}
|
||||
|
||||
public void DisplaySizeInfo(Graphics2D graphics2D, Vector2 widthDisplayCenter, double size)
|
||||
{
|
||||
string displayString = formatString.FormatWith(size);
|
||||
if (measureDisplayImage == null || measureDisplayedString != displayString)
|
||||
{
|
||||
measureDisplayedString = displayString;
|
||||
TypeFacePrinter printer = new TypeFacePrinter(measureDisplayedString, 16);
|
||||
TypeFacePrinter unitPrinter = new TypeFacePrinter(unitsString, 10);
|
||||
Double unitPrinterOffset = 1;
|
||||
|
||||
BorderDouble margin = new BorderDouble(5);
|
||||
printer.Origin = new Vector2(margin.Left, margin.Bottom);
|
||||
RectangleDouble bounds = printer.LocalBounds;
|
||||
|
||||
unitPrinter.Origin = new Vector2(bounds.Right + unitPrinterOffset, margin.Bottom);
|
||||
RectangleDouble unitPrinterBounds = unitPrinter.LocalBounds;
|
||||
|
||||
measureDisplayImage = new ImageBuffer((int)(bounds.Width + margin.Width + unitPrinterBounds.Width + unitPrinterOffset), (int)(bounds.Height + margin.Height));
|
||||
// make sure the texture has mipmaps (so it can reduce well)
|
||||
ImageGlPlugin glPlugin = ImageGlPlugin.GetImageGlPlugin(measureDisplayImage, true);
|
||||
Graphics2D widthGraphics = measureDisplayImage.NewGraphics2D();
|
||||
widthGraphics.Clear(new RGBA_Bytes(RGBA_Bytes.White, 128));
|
||||
printer.Render(widthGraphics, RGBA_Bytes.Black);
|
||||
unitPrinter.Render(widthGraphics, RGBA_Bytes.Black);
|
||||
}
|
||||
|
||||
widthDisplayCenter -= new Vector2(measureDisplayImage.Width / 2, measureDisplayImage.Height / 2);
|
||||
graphics2D.Render(measureDisplayImage, widthDisplayCenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
888
PartPreviewWindow/View3D/MeshViewerWidget.cs
Normal file
888
PartPreviewWindow/View3D/MeshViewerWidget.cs
Normal file
|
|
@ -0,0 +1,888 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.OpenGlGui;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.RayTracer;
|
||||
using MatterHackers.RayTracer.Traceable;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.RenderOpenGl.OpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace MatterHackers.MeshVisualizer
|
||||
{
|
||||
public enum BedShape { Rectangular, Circular };
|
||||
|
||||
public class DrawGlContentEventArgs : EventArgs
|
||||
{
|
||||
public bool ZBuffered { get; }
|
||||
|
||||
public DrawGlContentEventArgs(bool zBuffered)
|
||||
{
|
||||
ZBuffered = zBuffered;
|
||||
}
|
||||
}
|
||||
|
||||
public class MeshViewerWidget : GuiWidget
|
||||
{
|
||||
static public ImageBuffer BedImage = null;
|
||||
public List<InteractionVolume> interactionVolumes = new List<InteractionVolume>();
|
||||
public InteractionVolume SelectedInteractionVolume { get; set; } = null;
|
||||
public bool MouseDownOnInteractionVolume { get { return SelectedInteractionVolume != null; } }
|
||||
|
||||
public PartProcessingInfo partProcessingInfo;
|
||||
private static ImageBuffer lastCreatedBedImage = new ImageBuffer();
|
||||
|
||||
private static Dictionary<int, RGBA_Bytes> materialColors = new Dictionary<int, RGBA_Bytes>();
|
||||
private RGBA_Bytes bedBaseColor = new RGBA_Bytes(245, 245, 255);
|
||||
static public Vector2 BedCenter { get; private set; }
|
||||
private RGBA_Bytes bedMarkingsColor = RGBA_Bytes.Black;
|
||||
private static BedShape bedShape = BedShape.Rectangular;
|
||||
private static Mesh buildVolume = null;
|
||||
private static Vector3 displayVolume;
|
||||
private static Mesh printerBed = null;
|
||||
private RenderTypes renderType = RenderTypes.Shaded;
|
||||
|
||||
public double SnapGridDistance { get; set; } = 1;
|
||||
|
||||
private TrackballTumbleWidget trackballTumbleWidget;
|
||||
|
||||
private int volumeIndexWithMouseDown = -1;
|
||||
|
||||
public MeshViewerWidget(Vector3 displayVolume, Vector2 bedCenter, BedShape bedShape, string startingTextMessage = "")
|
||||
{
|
||||
Scene.SelectionChanged += (sender, e) =>
|
||||
{
|
||||
Invalidate();
|
||||
};
|
||||
RenderType = RenderTypes.Shaded;
|
||||
RenderBed = true;
|
||||
RenderBuildVolume = false;
|
||||
//SetMaterialColor(1, RGBA_Bytes.LightGray, RGBA_Bytes.White);
|
||||
BedColor = new RGBA_Floats(.8, .8, .8, .7).GetAsRGBA_Bytes();
|
||||
BuildVolumeColor = new RGBA_Floats(.2, .8, .3, .2).GetAsRGBA_Bytes();
|
||||
|
||||
trackballTumbleWidget = new TrackballTumbleWidget(this.World);
|
||||
trackballTumbleWidget.DrawRotationHelperCircle = false;
|
||||
trackballTumbleWidget.DrawGlContent += trackballTumbleWidget_DrawGlContent;
|
||||
trackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation;
|
||||
|
||||
AddChild(trackballTumbleWidget);
|
||||
|
||||
CreatePrintBed(displayVolume, bedCenter, bedShape);
|
||||
|
||||
trackballTumbleWidget.AnchorAll();
|
||||
|
||||
partProcessingInfo = new PartProcessingInfo(startingTextMessage);
|
||||
|
||||
GuiWidget labelContainer = new GuiWidget();
|
||||
labelContainer.AnchorAll();
|
||||
labelContainer.AddChild(partProcessingInfo);
|
||||
labelContainer.Selectable = false;
|
||||
|
||||
SetMaterialColor(1, ActiveTheme.Instance.PrimaryAccentColor);
|
||||
|
||||
this.AddChild(labelContainer);
|
||||
}
|
||||
|
||||
public WorldView World { get; } = new WorldView(0, 0);
|
||||
|
||||
public event EventHandler LoadDone;
|
||||
|
||||
public bool AllowBedRenderingWhenEmpty { get; set; }
|
||||
|
||||
public RGBA_Bytes BedColor { get; set; }
|
||||
|
||||
public RGBA_Bytes BuildVolumeColor { get; set; }
|
||||
|
||||
public Vector3 DisplayVolume { get { return displayVolume; } }
|
||||
|
||||
public static AxisAlignedBoundingBox GetAxisAlignedBoundingBox(List<MeshGroup> meshGroups)
|
||||
{
|
||||
AxisAlignedBoundingBox totalMeshBounds = AxisAlignedBoundingBox.Empty;
|
||||
bool first = true;
|
||||
foreach (MeshGroup meshGroup in meshGroups)
|
||||
{
|
||||
AxisAlignedBoundingBox meshBounds = meshGroup.GetAxisAlignedBoundingBox();
|
||||
if (first)
|
||||
{
|
||||
totalMeshBounds = meshBounds;
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
totalMeshBounds = AxisAlignedBoundingBox.Union(totalMeshBounds, meshBounds);
|
||||
}
|
||||
}
|
||||
|
||||
return totalMeshBounds;
|
||||
}
|
||||
|
||||
public override void OnLoad(EventArgs args)
|
||||
{
|
||||
// some debug code to be able to click on parts
|
||||
if (false)
|
||||
{
|
||||
AfterDraw += (sender, e) =>
|
||||
{
|
||||
foreach (var child in Scene.Children)
|
||||
{
|
||||
this.World.RenderDebugAABB(e.graphics2D, child.TraceData().GetAxisAlignedBoundingBox());
|
||||
this.World.RenderDebugAABB(e.graphics2D, child.GetAxisAlignedBoundingBox(Matrix4X4.Identity));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
base.OnLoad(args);
|
||||
}
|
||||
|
||||
|
||||
public override void FindNamedChildrenRecursive(string nameToSearchFor, List<WidgetAndPosition> foundChildren, RectangleDouble touchingBounds, SearchType seachType, bool allowInvalidItems = true)
|
||||
{
|
||||
foreach (var child in Scene.Children)
|
||||
{
|
||||
string object3DName = child.Name;
|
||||
if (object3DName == null && child.MeshPath != null)
|
||||
{
|
||||
object3DName = Path.GetFileName(child.MeshPath);
|
||||
}
|
||||
|
||||
bool nameFound = false;
|
||||
|
||||
if (seachType == SearchType.Exact)
|
||||
{
|
||||
if (object3DName == nameToSearchFor)
|
||||
{
|
||||
nameFound = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nameToSearchFor == ""
|
||||
|| object3DName.Contains(nameToSearchFor))
|
||||
{
|
||||
nameFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nameFound)
|
||||
{
|
||||
AxisAlignedBoundingBox bounds = child.TraceData().GetAxisAlignedBoundingBox();
|
||||
|
||||
RectangleDouble screenBoundsOfObject3D = RectangleDouble.ZeroIntersection;
|
||||
for(int i=0; i<4; i++)
|
||||
{
|
||||
screenBoundsOfObject3D.ExpandToInclude(this.World.GetScreenPosition(bounds.GetTopCorner(i)));
|
||||
screenBoundsOfObject3D.ExpandToInclude(this.World.GetScreenPosition(bounds.GetBottomCorner(i)));
|
||||
}
|
||||
|
||||
if (touchingBounds.IsTouching(screenBoundsOfObject3D))
|
||||
{
|
||||
Vector3 renderPosition = bounds.Center;
|
||||
Vector2 objectCenterScreenSpace = this.World.GetScreenPosition(renderPosition);
|
||||
Point2D screenPositionOfObject3D = new Point2D((int)objectCenterScreenSpace.x, (int)objectCenterScreenSpace.y);
|
||||
|
||||
foundChildren.Add(new WidgetAndPosition(this, screenPositionOfObject3D, object3DName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.FindNamedChildrenRecursive(nameToSearchFor, foundChildren, touchingBounds, seachType, allowInvalidItems);
|
||||
}
|
||||
|
||||
public InteractiveScene Scene { get; } = new InteractiveScene();
|
||||
|
||||
public Mesh PrinterBed { get { return printerBed; } }
|
||||
|
||||
public bool RenderBed { get; set; }
|
||||
|
||||
public bool RenderBuildVolume { get; set; }
|
||||
|
||||
public RenderTypes RenderType
|
||||
{
|
||||
get { return renderType; }
|
||||
set
|
||||
{
|
||||
if (renderType != value)
|
||||
{
|
||||
renderType = value;
|
||||
foreach(var renderTransfrom in Scene.VisibleMeshes(Matrix4X4.Identity))
|
||||
{
|
||||
renderTransfrom.MeshData.MarkAsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TrackballTumbleWidget TrackballTumbleWidget
|
||||
{
|
||||
get
|
||||
{
|
||||
return trackballTumbleWidget;
|
||||
}
|
||||
}
|
||||
|
||||
public static void AssertDebugNotDefined()
|
||||
{
|
||||
#if DEBUG
|
||||
throw new Exception("DEBUG is defined and should not be!");
|
||||
#endif
|
||||
}
|
||||
|
||||
public static RGBA_Bytes GetMaterialColor(int materialIndexBase1)
|
||||
{
|
||||
lock (materialColors)
|
||||
{
|
||||
if (materialColors.ContainsKey(materialIndexBase1))
|
||||
{
|
||||
return materialColors[materialIndexBase1];
|
||||
}
|
||||
}
|
||||
|
||||
// we currently expect at most 4 extruders
|
||||
return RGBA_Floats.FromHSL((materialIndexBase1 % 4) / 4.0, .5, .5).GetAsRGBA_Bytes();
|
||||
}
|
||||
|
||||
public static RGBA_Bytes GetSelectedMaterialColor(int materialIndexBase1)
|
||||
{
|
||||
double hue0To1;
|
||||
double saturation0To1;
|
||||
double lightness0To1;
|
||||
GetMaterialColor(materialIndexBase1).GetAsRGBA_Floats().GetHSL(out hue0To1, out saturation0To1, out lightness0To1);
|
||||
|
||||
// now make it a bit lighter and less saturated
|
||||
saturation0To1 = Math.Min(1, saturation0To1 * 2);
|
||||
lightness0To1 = Math.Min(1, lightness0To1 * 1.2);
|
||||
|
||||
// we sort of expect at most 4 extruders
|
||||
return RGBA_Floats.FromHSL(hue0To1, saturation0To1, lightness0To1).GetAsRGBA_Bytes();
|
||||
}
|
||||
|
||||
public static void SetMaterialColor(int materialIndexBase1, RGBA_Bytes color)
|
||||
{
|
||||
lock (materialColors)
|
||||
{
|
||||
if (!materialColors.ContainsKey(materialIndexBase1))
|
||||
{
|
||||
materialColors.Add(materialIndexBase1, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
materialColors[materialIndexBase1] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateGlDataObject(IObject3D item)
|
||||
{
|
||||
if(item.Mesh != null)
|
||||
{
|
||||
GLMeshTrianglePlugin.Get(item.Mesh);
|
||||
}
|
||||
|
||||
foreach (IObject3D child in item.Children.Where(o => o.Mesh != null))
|
||||
{
|
||||
GLMeshTrianglePlugin.Get(child.Mesh);
|
||||
}
|
||||
}
|
||||
|
||||
public void CreatePrintBed(Vector3 displayVolume, Vector2 bedCenter, BedShape bedShape)
|
||||
{
|
||||
if (MeshViewerWidget.BedCenter == bedCenter
|
||||
&& MeshViewerWidget.bedShape == bedShape
|
||||
&& MeshViewerWidget.displayVolume == displayVolume)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MeshViewerWidget.BedCenter = bedCenter;
|
||||
MeshViewerWidget.bedShape = bedShape;
|
||||
MeshViewerWidget.displayVolume = displayVolume;
|
||||
Vector3 displayVolumeToBuild = Vector3.ComponentMax(displayVolume, new Vector3(1, 1, 1));
|
||||
|
||||
double sizeForMarking = Math.Max(displayVolumeToBuild.x, displayVolumeToBuild.y);
|
||||
double divisor = 10;
|
||||
int skip = 1;
|
||||
if (sizeForMarking > 1000)
|
||||
{
|
||||
divisor = 100;
|
||||
skip = 10;
|
||||
}
|
||||
else if (sizeForMarking > 300)
|
||||
{
|
||||
divisor = 50;
|
||||
skip = 5;
|
||||
}
|
||||
|
||||
switch (bedShape)
|
||||
{
|
||||
case BedShape.Rectangular:
|
||||
if (displayVolumeToBuild.z > 0)
|
||||
{
|
||||
buildVolume = PlatonicSolids.CreateCube(displayVolumeToBuild);
|
||||
foreach (Vertex vertex in buildVolume.Vertices)
|
||||
{
|
||||
vertex.Position = vertex.Position + new Vector3(0, 0, displayVolumeToBuild.z / 2);
|
||||
}
|
||||
}
|
||||
CreateRectangularBedGridImage(displayVolumeToBuild, bedCenter, divisor, skip);
|
||||
printerBed = PlatonicSolids.CreateCube(displayVolumeToBuild.x, displayVolumeToBuild.y, 1.8);
|
||||
{
|
||||
Face face = printerBed.Faces[0];
|
||||
MeshHelper.PlaceTextureOnFace(face, BedImage);
|
||||
}
|
||||
break;
|
||||
|
||||
case BedShape.Circular:
|
||||
{
|
||||
if (displayVolumeToBuild.z > 0)
|
||||
{
|
||||
buildVolume = VertexSourceToMesh.Extrude(new Ellipse(new Vector2(), displayVolumeToBuild.x / 2, displayVolumeToBuild.y / 2), displayVolumeToBuild.z);
|
||||
foreach (Vertex vertex in buildVolume.Vertices)
|
||||
{
|
||||
vertex.Position = vertex.Position + new Vector3(0, 0, .2);
|
||||
}
|
||||
}
|
||||
CreateCircularBedGridImage((int)(displayVolumeToBuild.x / divisor), (int)(displayVolumeToBuild.y / divisor), skip);
|
||||
printerBed = VertexSourceToMesh.Extrude(new Ellipse(new Vector2(), displayVolumeToBuild.x / 2, displayVolumeToBuild.y / 2), 2);
|
||||
{
|
||||
foreach (Face face in printerBed.Faces)
|
||||
{
|
||||
if (face.normal.z > 0)
|
||||
{
|
||||
FaceTextureData faceData = FaceTextureData.Get(face);
|
||||
faceData.Textures.Add(BedImage);
|
||||
foreach (FaceEdge faceEdge in face.FaceEdges())
|
||||
{
|
||||
FaceEdgeTextureUvData edgeUV = FaceEdgeTextureUvData.Get(faceEdge);
|
||||
edgeUV.TextureUV.Add(new Vector2((displayVolumeToBuild.x / 2 + faceEdge.firstVertex.Position.x) / displayVolumeToBuild.x,
|
||||
(displayVolumeToBuild.y / 2 + faceEdge.firstVertex.Position.y) / displayVolumeToBuild.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
foreach (Vertex vertex in printerBed.Vertices)
|
||||
{
|
||||
vertex.Position = vertex.Position - new Vector3(-bedCenter, 2.2);
|
||||
}
|
||||
|
||||
if (buildVolume != null)
|
||||
{
|
||||
foreach (Vertex vertex in buildVolume.Vertices)
|
||||
{
|
||||
vertex.Position = vertex.Position - new Vector3(-bedCenter, 2.2);
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
public bool SuppressUiVolumes { get; set; } = false;
|
||||
|
||||
public async Task LoadItemIntoScene(string itemPath, Vector2 bedCenter = new Vector2(), string itemName = null)
|
||||
{
|
||||
if (File.Exists(itemPath))
|
||||
{
|
||||
BeginProgressReporting("Loading Mesh");
|
||||
|
||||
// TODO: How to we handle mesh load errors? How do we report success?
|
||||
IObject3D loadedItem = await Task.Run(() => Object3D.Load(itemPath, progress: ReportProgress0to100));
|
||||
if (loadedItem != null)
|
||||
{
|
||||
if (itemName != null)
|
||||
{
|
||||
loadedItem.Name = itemName;
|
||||
}
|
||||
|
||||
// SetMeshAfterLoad
|
||||
Scene.ModifyChildren(children =>
|
||||
{
|
||||
if (loadedItem.Mesh != null)
|
||||
{
|
||||
// STLs currently load directly into the mesh rather than as a group like AMF
|
||||
children.Add(loadedItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
children.AddRange(loadedItem.Children);
|
||||
}
|
||||
});
|
||||
|
||||
CreateGlDataObject(loadedItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
partProcessingInfo.centeredInfoText.Text = string.Format("Sorry! No 3D view available\nfor this file.");
|
||||
}
|
||||
|
||||
EndProgressReporting();
|
||||
|
||||
// Invoke LoadDone event
|
||||
LoadDone?.Invoke(this, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
partProcessingInfo.centeredInfoText.Text = string.Format("{0}\n'{1}'", "File not found on disk.", Path.GetFileName(itemPath));
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDraw(Graphics2D graphics2D)
|
||||
{
|
||||
base.OnDraw(graphics2D);
|
||||
|
||||
//if (!SuppressUiVolumes)
|
||||
{
|
||||
foreach (InteractionVolume interactionVolume in interactionVolumes)
|
||||
{
|
||||
interactionVolume.Draw2DContent(graphics2D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMouseDown(MouseEventArgs mouseEvent)
|
||||
{
|
||||
base.OnMouseDown(mouseEvent);
|
||||
|
||||
if (trackballTumbleWidget.MouseCaptured)
|
||||
{
|
||||
if (trackballTumbleWidget.TransformState == TrackBallController.MouseDownType.Rotation || mouseEvent.Button == MouseButtons.Right)
|
||||
{
|
||||
trackballTumbleWidget.DrawRotationHelperCircle = true;
|
||||
}
|
||||
}
|
||||
|
||||
int volumeHitIndex;
|
||||
Ray ray = this.World.GetRayForLocalBounds(mouseEvent.Position);
|
||||
IntersectInfo info;
|
||||
if (this.Scene.HasSelection
|
||||
&& !SuppressUiVolumes
|
||||
&& FindInteractionVolumeHit(ray, out volumeHitIndex, out info))
|
||||
{
|
||||
MouseEvent3DArgs mouseEvent3D = new MouseEvent3DArgs(mouseEvent, ray, info);
|
||||
volumeIndexWithMouseDown = volumeHitIndex;
|
||||
interactionVolumes[volumeHitIndex].OnMouseDown(mouseEvent3D);
|
||||
SelectedInteractionVolume = interactionVolumes[volumeHitIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedInteractionVolume = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMouseMove(MouseEventArgs mouseEvent)
|
||||
{
|
||||
base.OnMouseMove(mouseEvent);
|
||||
|
||||
if (SuppressUiVolumes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Ray ray = this.World.GetRayForLocalBounds(mouseEvent.Position);
|
||||
IntersectInfo info = null;
|
||||
if (MouseDownOnInteractionVolume && volumeIndexWithMouseDown != -1)
|
||||
{
|
||||
MouseEvent3DArgs mouseEvent3D = new MouseEvent3DArgs(mouseEvent, ray, info);
|
||||
interactionVolumes[volumeIndexWithMouseDown].OnMouseMove(mouseEvent3D);
|
||||
}
|
||||
else
|
||||
{
|
||||
MouseEvent3DArgs mouseEvent3D = new MouseEvent3DArgs(mouseEvent, ray, info);
|
||||
|
||||
int volumeHitIndex;
|
||||
FindInteractionVolumeHit(ray, out volumeHitIndex, out info);
|
||||
|
||||
for (int i = 0; i < interactionVolumes.Count; i++)
|
||||
{
|
||||
if (i == volumeHitIndex)
|
||||
{
|
||||
interactionVolumes[i].MouseOver = true;
|
||||
interactionVolumes[i].MouseMoveInfo = info;
|
||||
}
|
||||
else
|
||||
{
|
||||
interactionVolumes[i].MouseOver = false;
|
||||
interactionVolumes[i].MouseMoveInfo = null;
|
||||
}
|
||||
|
||||
interactionVolumes[i].OnMouseMove(mouseEvent3D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMouseUp(MouseEventArgs mouseEvent)
|
||||
{
|
||||
trackballTumbleWidget.DrawRotationHelperCircle = false;
|
||||
Invalidate();
|
||||
|
||||
if(SuppressUiVolumes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int volumeHitIndex;
|
||||
Ray ray = this.World.GetRayForLocalBounds(mouseEvent.Position);
|
||||
IntersectInfo info;
|
||||
bool anyInteractionVolumeHit = FindInteractionVolumeHit(ray, out volumeHitIndex, out info);
|
||||
MouseEvent3DArgs mouseEvent3D = new MouseEvent3DArgs(mouseEvent, ray, info);
|
||||
|
||||
if (MouseDownOnInteractionVolume && volumeIndexWithMouseDown != -1)
|
||||
{
|
||||
interactionVolumes[volumeIndexWithMouseDown].OnMouseUp(mouseEvent3D);
|
||||
SelectedInteractionVolume = null;
|
||||
|
||||
volumeIndexWithMouseDown = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
volumeIndexWithMouseDown = -1;
|
||||
|
||||
if (anyInteractionVolumeHit)
|
||||
{
|
||||
interactionVolumes[volumeHitIndex].OnMouseUp(mouseEvent3D);
|
||||
}
|
||||
SelectedInteractionVolume = null;
|
||||
}
|
||||
|
||||
base.OnMouseUp(mouseEvent);
|
||||
}
|
||||
|
||||
public void ResetView()
|
||||
{
|
||||
trackballTumbleWidget.ZeroVelocity();
|
||||
|
||||
this.World.Reset();
|
||||
this.World.Scale = .03;
|
||||
this.World.Translate(-new Vector3(BedCenter));
|
||||
this.World.Rotate(Quaternion.FromEulerAngles(new Vector3(0, 0, MathHelper.Tau / 16)));
|
||||
this.World.Rotate(Quaternion.FromEulerAngles(new Vector3(-MathHelper.Tau * .19, 0, 0)));
|
||||
}
|
||||
|
||||
private void CreateCircularBedGridImage(int linesInX, int linesInY, int increment = 1)
|
||||
{
|
||||
Vector2 bedImageCentimeters = new Vector2(linesInX, linesInY);
|
||||
BedImage = new ImageBuffer(1024, 1024);
|
||||
Graphics2D graphics2D = BedImage.NewGraphics2D();
|
||||
graphics2D.Clear(bedBaseColor);
|
||||
{
|
||||
double lineDist = BedImage.Width / (double)linesInX;
|
||||
|
||||
int count = 1;
|
||||
int pointSize = 16;
|
||||
graphics2D.DrawString(count.ToString(), 4, 4, pointSize, color: bedMarkingsColor);
|
||||
double currentRadius = lineDist;
|
||||
Vector2 bedCenter = new Vector2(BedImage.Width / 2, BedImage.Height / 2);
|
||||
for (double linePos = lineDist + BedImage.Width / 2; linePos < BedImage.Width; linePos += lineDist)
|
||||
{
|
||||
int linePosInt = (int)linePos;
|
||||
graphics2D.DrawString((count * increment).ToString(), linePos + 2, BedImage.Height / 2, pointSize, color: bedMarkingsColor);
|
||||
|
||||
Ellipse circle = new Ellipse(bedCenter, currentRadius);
|
||||
Stroke outline = new Stroke(circle);
|
||||
graphics2D.Render(outline, bedMarkingsColor);
|
||||
currentRadius += lineDist;
|
||||
count++;
|
||||
}
|
||||
|
||||
graphics2D.Line(0, BedImage.Height / 2, BedImage.Width, BedImage.Height / 2, bedMarkingsColor);
|
||||
graphics2D.Line(BedImage.Width / 2, 0, BedImage.Width / 2, BedImage.Height, bedMarkingsColor);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateRectangularBedGridImage(Vector3 displayVolumeToBuild, Vector2 bedCenter, double divisor, double skip)
|
||||
{
|
||||
lock (lastCreatedBedImage)
|
||||
{
|
||||
BedImage = new ImageBuffer(1024, 1024);
|
||||
Graphics2D graphics2D = BedImage.NewGraphics2D();
|
||||
graphics2D.Clear(bedBaseColor);
|
||||
{
|
||||
double lineDist = BedImage.Width / (displayVolumeToBuild.x / divisor);
|
||||
|
||||
double xPositionCm = (-(displayVolume.x / 2.0) + bedCenter.x) / divisor;
|
||||
int xPositionCmInt = (int)Math.Round(xPositionCm);
|
||||
double fraction = xPositionCm - xPositionCmInt;
|
||||
int pointSize = 20;
|
||||
graphics2D.DrawString((xPositionCmInt * skip).ToString(), 4, 4, pointSize, color: bedMarkingsColor);
|
||||
for (double linePos = lineDist * (1 - fraction); linePos < BedImage.Width; linePos += lineDist)
|
||||
{
|
||||
xPositionCmInt++;
|
||||
int linePosInt = (int)linePos;
|
||||
int lineWidth = 1;
|
||||
if (xPositionCmInt == 0)
|
||||
{
|
||||
lineWidth = 2;
|
||||
}
|
||||
graphics2D.Line(linePosInt, 0, linePosInt, BedImage.Height, bedMarkingsColor, lineWidth);
|
||||
graphics2D.DrawString((xPositionCmInt * skip).ToString(), linePos + 4, 4, pointSize, color: bedMarkingsColor);
|
||||
}
|
||||
}
|
||||
{
|
||||
double lineDist = BedImage.Height / (displayVolumeToBuild.y / divisor);
|
||||
|
||||
double yPositionCm = (-(displayVolume.y / 2.0) + bedCenter.y) / divisor;
|
||||
int yPositionCmInt = (int)Math.Round(yPositionCm);
|
||||
double fraction = yPositionCm - yPositionCmInt;
|
||||
int pointSize = 20;
|
||||
for (double linePos = lineDist * (1 - fraction); linePos < BedImage.Height; linePos += lineDist)
|
||||
{
|
||||
yPositionCmInt++;
|
||||
int linePosInt = (int)linePos;
|
||||
int lineWidth = 1;
|
||||
if (yPositionCmInt == 0)
|
||||
{
|
||||
lineWidth = 2;
|
||||
}
|
||||
graphics2D.Line(0, linePosInt, BedImage.Height, linePosInt, bedMarkingsColor, lineWidth);
|
||||
|
||||
graphics2D.DrawString((yPositionCmInt * skip).ToString(), 4, linePos + 4, pointSize, color: bedMarkingsColor);
|
||||
}
|
||||
}
|
||||
|
||||
lastCreatedBedImage = BedImage;
|
||||
}
|
||||
}
|
||||
|
||||
private bool FindInteractionVolumeHit(Ray ray, out int interactionVolumeHitIndex, out IntersectInfo info)
|
||||
{
|
||||
interactionVolumeHitIndex = -1;
|
||||
if (interactionVolumes.Count == 0 || interactionVolumes[0].CollisionVolume == null)
|
||||
{
|
||||
info = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
List<IPrimitive> uiTraceables = new List<IPrimitive>();
|
||||
foreach (InteractionVolume interactionVolume in interactionVolumes)
|
||||
{
|
||||
if (interactionVolume.CollisionVolume != null)
|
||||
{
|
||||
IPrimitive traceData = interactionVolume.CollisionVolume;
|
||||
uiTraceables.Add(new Transform(traceData, interactionVolume.TotalTransform));
|
||||
}
|
||||
}
|
||||
IPrimitive allUiObjects = BoundingVolumeHierarchy.CreateNewHierachy(uiTraceables);
|
||||
|
||||
info = allUiObjects.GetClosestIntersection(ray);
|
||||
if (info != null)
|
||||
{
|
||||
for (int i = 0; i < interactionVolumes.Count; i++)
|
||||
{
|
||||
List<IBvhItem> insideBounds = new List<IBvhItem>();
|
||||
if (interactionVolumes[i].CollisionVolume != null)
|
||||
{
|
||||
interactionVolumes[i].CollisionVolume.GetContained(insideBounds, info.closestHitObject.GetAxisAlignedBoundingBox());
|
||||
if (insideBounds.Contains(info.closestHitObject))
|
||||
{
|
||||
interactionVolumeHitIndex = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string progressReportingPrimaryTask = "";
|
||||
|
||||
public void BeginProgressReporting(string taskDescription)
|
||||
{
|
||||
progressReportingPrimaryTask = taskDescription;
|
||||
|
||||
partProcessingInfo.Visible = true;
|
||||
partProcessingInfo.progressControl.PercentComplete = 0;
|
||||
partProcessingInfo.centeredInfoText.Text = taskDescription + "...";
|
||||
}
|
||||
|
||||
public void EndProgressReporting()
|
||||
{
|
||||
progressReportingPrimaryTask = "";
|
||||
partProcessingInfo.Visible = false;
|
||||
}
|
||||
|
||||
public void ReportProgress0to100(double progress0To1, string processingState, out bool continueProcessing)
|
||||
{
|
||||
if (this.HasBeenClosed)
|
||||
{
|
||||
continueProcessing = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
continueProcessing = true;
|
||||
}
|
||||
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
int percentComplete = (int)(progress0To1 * 100);
|
||||
partProcessingInfo.centeredInfoText.Text = "{0} {1}%...".FormatWith(progressReportingPrimaryTask, percentComplete);
|
||||
partProcessingInfo.progressControl.PercentComplete = percentComplete;
|
||||
|
||||
// Only assign to textbox if value passed through
|
||||
if (processingState != null)
|
||||
{
|
||||
partProcessingInfo.centeredInfoDescription.Text = processingState;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawObject(IObject3D object3D, Matrix4X4 transform, bool parentSelected)
|
||||
{
|
||||
foreach(MeshAndTransform meshAndTransform in object3D.VisibleMeshes(transform))
|
||||
{
|
||||
bool isSelected = parentSelected ||
|
||||
Scene.HasSelection && (object3D == Scene.SelectedItem || Scene.SelectedItem.Children.Contains(object3D));
|
||||
|
||||
MeshMaterialData meshData = MeshMaterialData.Get(meshAndTransform.MeshData);
|
||||
RGBA_Bytes drawColor = object3D.Color;
|
||||
if (drawColor.Alpha0To1 == 0)
|
||||
{
|
||||
drawColor = isSelected ? GetSelectedMaterialColor(meshData.MaterialIndex) : GetMaterialColor(meshData.MaterialIndex);
|
||||
}
|
||||
|
||||
GLHelper.Render(meshAndTransform.MeshData, drawColor, meshAndTransform.Matrix, RenderType);
|
||||
}
|
||||
}
|
||||
|
||||
private void trackballTumbleWidget_DrawGlContent(object sender, EventArgs e)
|
||||
{
|
||||
foreach(var object3D in Scene.Children)
|
||||
{
|
||||
DrawObject(object3D, Matrix4X4.Identity, false);
|
||||
}
|
||||
|
||||
if (RenderBed)
|
||||
{
|
||||
GLHelper.Render(printerBed, this.BedColor);
|
||||
}
|
||||
|
||||
if (buildVolume != null && RenderBuildVolume)
|
||||
{
|
||||
GLHelper.Render(buildVolume, this.BuildVolumeColor);
|
||||
}
|
||||
|
||||
// we don't want to render the bed or build volume before we load a model.
|
||||
if (Scene.HasChildren || AllowBedRenderingWhenEmpty)
|
||||
{
|
||||
if (false) // this is code to draw a small axis indicator
|
||||
{
|
||||
double big = 10;
|
||||
double small = 1;
|
||||
Mesh xAxis = PlatonicSolids.CreateCube(big, small, small);
|
||||
GLHelper.Render(xAxis, RGBA_Bytes.Red);
|
||||
Mesh yAxis = PlatonicSolids.CreateCube(small, big, small);
|
||||
GLHelper.Render(yAxis, RGBA_Bytes.Green);
|
||||
Mesh zAxis = PlatonicSolids.CreateCube(small, small, big);
|
||||
GLHelper.Render(zAxis, RGBA_Bytes.Blue);
|
||||
}
|
||||
}
|
||||
|
||||
DrawInteractionVolumes(e);
|
||||
}
|
||||
|
||||
private void DrawInteractionVolumes(EventArgs e)
|
||||
{
|
||||
if(SuppressUiVolumes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// draw on top of anything that is already drawn
|
||||
foreach (InteractionVolume interactionVolume in interactionVolumes)
|
||||
{
|
||||
if (interactionVolume.DrawOnTop)
|
||||
{
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
interactionVolume.DrawGlContent(new DrawGlContentEventArgs(false));
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw again setting the depth buffer and ensuring that all the interaction objects are sorted as well as we can
|
||||
foreach (InteractionVolume interactionVolume in interactionVolumes)
|
||||
{
|
||||
interactionVolume.DrawGlContent(new DrawGlContentEventArgs(true));
|
||||
}
|
||||
}
|
||||
|
||||
public class PartProcessingInfo : FlowLayoutWidget
|
||||
{
|
||||
internal TextWidget centeredInfoDescription;
|
||||
internal TextWidget centeredInfoText;
|
||||
internal ProgressControl progressControl;
|
||||
|
||||
internal PartProcessingInfo(string startingTextMessage)
|
||||
: base(FlowDirection.TopToBottom)
|
||||
{
|
||||
progressControl = new ProgressControl("", RGBA_Bytes.Black, RGBA_Bytes.Black);
|
||||
progressControl.HAnchor = HAnchor.ParentCenter;
|
||||
AddChild(progressControl);
|
||||
progressControl.Visible = false;
|
||||
progressControl.ProgressChanged += (sender, e) =>
|
||||
{
|
||||
progressControl.Visible = true;
|
||||
};
|
||||
|
||||
centeredInfoText = new TextWidget(startingTextMessage);
|
||||
centeredInfoText.HAnchor = HAnchor.ParentCenter;
|
||||
centeredInfoText.AutoExpandBoundsToText = true;
|
||||
AddChild(centeredInfoText);
|
||||
|
||||
centeredInfoDescription = new TextWidget("");
|
||||
centeredInfoDescription.HAnchor = HAnchor.ParentCenter;
|
||||
centeredInfoDescription.AutoExpandBoundsToText = true;
|
||||
AddChild(centeredInfoDescription);
|
||||
|
||||
VAnchor |= VAnchor.ParentCenter;
|
||||
HAnchor |= HAnchor.ParentCenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
PartPreviewWindow/View3D/MouseEvent3DArgs.cs
Normal file
52
PartPreviewWindow/View3D/MouseEvent3DArgs.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.RayTracer;
|
||||
using MatterHackers.VectorMath;
|
||||
using System;
|
||||
|
||||
namespace MatterHackers.MeshVisualizer
|
||||
{
|
||||
public class MouseEvent3DArgs : EventArgs
|
||||
{
|
||||
public IntersectInfo info;
|
||||
public MouseEventArgs MouseEvent2D;
|
||||
private Ray mouseRay;
|
||||
|
||||
public Ray MouseRay { get { return mouseRay; } }
|
||||
|
||||
public MouseEvent3DArgs(MouseEventArgs mouseEvent2D, Ray mouseRay, IntersectInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
this.MouseEvent2D = mouseEvent2D;
|
||||
this.mouseRay = mouseRay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,6 @@ either expressed or implied, of the FreeBSD Project.
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
|
@ -434,7 +433,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
GetRenderType(),
|
||||
gcodeViewWidget.FeatureToStartOnRatio0To1,
|
||||
gcodeViewWidget.FeatureToEndOnRatio0To1,
|
||||
new Vector2[] { ActiveSliceSettings.Instance.Helpers.ExtruderOffset(0), ActiveSliceSettings.Instance.Helpers.ExtruderOffset(1) });
|
||||
new Vector2[] { ActiveSliceSettings.Instance.Helpers.ExtruderOffset(0), ActiveSliceSettings.Instance.Helpers.ExtruderOffset(1) },
|
||||
MeshViewerWidget.GetMaterialColor);
|
||||
|
||||
gcodeViewWidget.gCodeRenderer.Render3D(renderInfo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,20 +27,20 @@ of the authors and should not be interpreted as representing official policies,
|
|||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Transform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.GCodeVisualizer;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.SlicerConfiguration;
|
||||
using MatterHackers.MeshVisualizer;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.RenderOpenGl.OpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using MatterHackers.Localizations;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow
|
||||
{
|
||||
|
|
@ -299,7 +299,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
|
||||
GCodeRenderInfo renderInfo = new GCodeRenderInfo(activeLayerIndex, activeLayerIndex, transform, layerScale, CreateRenderInfo(),
|
||||
FeatureToStartOnRatio0To1, FeatureToEndOnRatio0To1,
|
||||
new Vector2[] { ActiveSliceSettings.Instance.Helpers.ExtruderOffset(0), ActiveSliceSettings.Instance.Helpers.ExtruderOffset(1) });
|
||||
new Vector2[] { ActiveSliceSettings.Instance.Helpers.ExtruderOffset(0), ActiveSliceSettings.Instance.Helpers.ExtruderOffset(1) },
|
||||
MeshViewerWidget.GetMaterialColor);
|
||||
|
||||
//using (new PerformanceTimer("GCode Timer", "Render"))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -83,6 +83,10 @@
|
|||
<Project>{0B8D6F56-BD7F-4426-B858-D9292B084656}</Project>
|
||||
<Name>MatterControl</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\MatterControl.Printing\MatterControl.Printing.csproj">
|
||||
<Project>{97d5ade3-c1b4-4b46-8a3e-718a4f7f079f}</Project>
|
||||
<Name>MatterControl.Printing</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\PrinterEmulator\PrinterEmulator.csproj">
|
||||
<Project>{bb58ca42-991b-41b7-bde7-dcd2911df8b9}</Project>
|
||||
<Name>PrinterEmulator</Name>
|
||||
|
|
@ -95,14 +99,6 @@
|
|||
<Project>{04667764-dc7b-4b95-aef6-b4e6c87a54e9}</Project>
|
||||
<Name>DataConverters3D</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Submodules\agg-sharp\examples\GCodeVisualizer\GCodeVisualizer.csproj">
|
||||
<Project>{F67AE800-B0C7-42A8-836F-597B4E74591C}</Project>
|
||||
<Name>GCodeVisualizer</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Submodules\agg-sharp\examples\MeshViewer\MeshViewer.csproj">
|
||||
<Project>{a737bc76-165b-46c6-82b7-8871c7c92942}</Project>
|
||||
<Name>MeshViewer</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Submodules\agg-sharp\GuiAutomation\GuiAutomation.csproj">
|
||||
<Project>{E9102310-0029-4D8F-B1E9-88FBA6147D45}</Project>
|
||||
<Name>GuiAutomation</Name>
|
||||
|
|
|
|||
|
|
@ -166,10 +166,6 @@
|
|||
<Project>{04667764-DC7B-4B95-AEF6-B4E6C87A54E9}</Project>
|
||||
<Name>DataConverters3D</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\examples\MeshViewer\MeshViewer.csproj">
|
||||
<Project>{A737BC76-165B-46C6-82B7-8871C7C92942}</Project>
|
||||
<Name>MeshViewer</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Submodules\agg-sharp\Gui\Gui.csproj">
|
||||
<Project>{74F6BB6C-9D02-4512-A59A-21940E35C532}</Project>
|
||||
<Name>Gui</Name>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue