Move MatterControl source code into a subdirectory

This commit is contained in:
Nettika 2026-01-28 21:30:58 -08:00
parent 2c6e34243a
commit 70af2d9ae8
No known key found for this signature in database
2007 changed files with 13 additions and 8 deletions

View 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, Color 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;
}
}
}

View file

@ -0,0 +1,91 @@
/*
Copyright (c) 2018, 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 System.Linq;
using MatterHackers.Agg;
namespace MatterHackers.GCodeVisualizer
{
public class ExtrusionColors
{
private Dictionary<float, Color> speedColors = new Dictionary<float, Color>();
private double startColor = 223.0 / 360.0;
private double endColor = 5.0 / 360.0;
private double range;
private double delta;
private float min;
private float max;
public ExtrusionColors(HashSet<float> speeds)
{
if (speeds.Any())
{
min = speeds.Min();
max = speeds.Max();
}
else
{
min = 0;
max = 1;
}
range = max - min;
delta = startColor - endColor;
foreach (var speed in speeds)
{
speedColors[speed] = this.ComputeColor(speed);
}
}
public Color GetColorForSpeed(float speed)
{
if (speedColors.TryGetValue(speed, out Color color))
{
return color;
}
// Compute value if missing from dictionary (legend uses non-existing speeds)
return this.ComputeColor(speed);
}
private Color ComputeColor(float speed)
{
var rangedValue = speed - min;
var factor = range == 0 ? 1 : rangedValue / range;
double offset = factor * delta;
double fixedColor = startColor - offset;
return ColorF.FromHSL(fixedColor, .99, .49).ToColor();
}
}
}

View file

@ -0,0 +1,88 @@
/*
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
{
public Func<int, Color> GetMaterialColor { get; }
public int StartLayerIndex { get; set; }
public int EndLayerIndex { get; set; }
public Affine Transform { get; }
public double LayerScale { get; }
public RenderType CurrentRenderType { get; private set; }
public double FeatureToStartOnRatio0To1 { get; set; }
public double FeatureToEndOnRatio0To1 { get; set; }
public Func<RenderType> GetRenderType { get; }
public GCodeRenderInfo()
{
}
public GCodeRenderInfo(int startLayerIndex, int endLayerIndex,
Affine transform, double layerScale,
double featureToStartOnRatio0To1, double featureToEndOnRatio0To1,
Func<RenderType> getRenderType,
Func<int, Color> getMaterialColor)
{
this.GetMaterialColor = getMaterialColor;
this.StartLayerIndex = startLayerIndex;
this.EndLayerIndex = endLayerIndex;
this.Transform = transform;
this.LayerScale = layerScale;
// Store delegate
this.GetRenderType = getRenderType;
// Invoke delegate
this.CurrentRenderType = this.GetRenderType();
this.FeatureToStartOnRatio0To1 = featureToStartOnRatio0To1;
this.FeatureToEndOnRatio0To1 = featureToEndOnRatio0To1;
}
public void RefreshRenderType()
{
this.CurrentRenderType = this.GetRenderType();
}
}
}

View file

@ -0,0 +1,457 @@
/*
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 MatterControl.Printing;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.RenderOpenGl;
using MatterHackers.RenderOpenGl.OpenGl;
using MatterHackers.VectorMath;
namespace MatterHackers.GCodeVisualizer
{
[Flags]
public enum RenderType
{
None = 0,
Extrusions = 1,
Moves = 2,
Retractions = 4,
SpeedColors = 8,
SimulateExtrusion = 16,
TransparentExtrusion = 64,
GrayColors = 128
};
public class GCodeRenderer : IDisposable
{
public static double ExtruderWidth { get; set; } = .4;
public static Color TravelColor = Color.Green;
public static Color RetractionColor = Color.FireEngineRed;
internal class Layer
{
internal List<int> startIndices = new List<int>();
internal List<int> endIndices = new List<int>();
internal List<RenderFeatureBase> features = new List<RenderFeatureBase>();
}
internal class FeatureSet
{
internal List<Layer> layers = new List<Layer>();
}
private FeatureSet all = new FeatureSet();
private List<GCodeVertexBuffer> layerVertexBuffer;
private RenderType lastRenderType = RenderType.None;
private GCodeFile gCodeFileToDraw;
public GCodeRenderer(GCodeFile gCodeFileToDraw)
{
if (gCodeFileToDraw != null)
{
this.gCodeFileToDraw = gCodeFileToDraw;
if (gCodeFileToDraw is GCodeMemoryFile memoryFile)
{
this.ExtrusionColors = new ExtrusionColors(memoryFile.Speeds);
}
for (int i = 0; i < gCodeFileToDraw.LayerCount; i++)
{
all.layers.Add(new Layer());
}
}
}
public GCodeFile GCodeFileToDraw => gCodeFileToDraw;
public ExtrusionColors ExtrusionColors { get; } = null;
public Color Gray { get; set; }
public void CreateFeaturesForLayerIfRequired(int layerToCreate)
{
if (all.layers.Count == 0
|| all.layers[layerToCreate].features.Count > 0)
{
return;
}
List<RenderFeatureBase> renderFeaturesForLayer = all.layers[layerToCreate].features;
int startRenderIndex = gCodeFileToDraw.GetFirstLayerInstruction(layerToCreate);
int endRenderIndex = gCodeFileToDraw.LineCount - 1;
if (layerToCreate < gCodeFileToDraw.LayerCount - 1)
{
endRenderIndex = gCodeFileToDraw.GetFirstLayerInstruction(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)
{
double eMovement = 0;
if (currentInstruction.PositionSet != PositionSet.E)
{
eMovement = currentInstruction.EPosition - previousInstruction.EPosition;
}
if (Math.Abs(eMovement) > 0)
{
// this is a retraction
renderFeaturesForLayer.Add(new RenderFeatureRetract(instructionIndex, currentInstruction.Position, eMovement, currentInstruction.ToolIndex, currentInstruction.FeedRate));
}
if (currentInstruction.Line.StartsWith("G10"))
{
renderFeaturesForLayer.Add(new RenderFeatureRetract(instructionIndex, currentInstruction.Position, -1, currentInstruction.ToolIndex, currentInstruction.FeedRate));
}
else if (currentInstruction.Line.StartsWith("G11"))
{
renderFeaturesForLayer.Add(new RenderFeatureRetract(instructionIndex, currentInstruction.Position, 1, currentInstruction.ToolIndex, currentInstruction.FeedRate));
}
}
else
{
var extrusionAmount = currentInstruction.EPosition - previousInstruction.EPosition;
var filamentDiameterMm = gCodeFileToDraw.GetFilamentDiameter();
if (gCodeFileToDraw.IsExtruding(instructionIndex))
{
double layerThickness = gCodeFileToDraw.GetLayerHeight(layerToCreate);
Color extrusionColor = ExtrusionColors.GetColorForSpeed((float)currentInstruction.FeedRate);
renderFeaturesForLayer.Add(
new RenderFeatureExtrusion(
instructionIndex,
previousInstruction.Position,
currentInstruction.Position,
currentInstruction.ToolIndex,
currentInstruction.FeedRate,
extrusionAmount,
filamentDiameterMm,
layerThickness,
extrusionColor,
this.Gray));
}
else
{
if (extrusionAmount < 0)
{
double moveLength = (currentInstruction.Position - previousInstruction.Position).Length;
double filamentRadius = filamentDiameterMm / 2;
double areaSquareMm = (filamentRadius * filamentRadius) * Math.PI;
var extrusionVolumeMm3 = (float)(areaSquareMm * extrusionAmount);
var area = extrusionVolumeMm3 / moveLength;
}
renderFeaturesForLayer.Add(
new RenderFeatureTravel(
instructionIndex,
previousInstruction.Position,
currentInstruction.Position,
currentInstruction.ToolIndex,
currentInstruction.FeedRate,
extrusionAmount < 0));
}
}
}
}
public int GetNumFeatures(int layerToCountFeaturesOn)
{
CreateFeaturesForLayerIfRequired(layerToCountFeaturesOn);
return all.layers[layerToCountFeaturesOn].features.Count;
}
public RenderFeatureBase this[int layerIndex, int featureIndex]
{
get
{
try
{
var features = all.layers[layerIndex].features;
if (featureIndex < features.Count)
{
return features[featureIndex];
}
}
catch
{
}
// Callers should test for non-null values
return null;
}
}
public bool GCodeInspector { get; set; } = false;
public void Render(Graphics2D graphics2D, GCodeRenderInfo renderInfo)
{
if (all.layers.Count > 0)
{
CreateFeaturesForLayerIfRequired(renderInfo.EndLayerIndex);
int featuresOnLayer = all.layers[renderInfo.EndLayerIndex].features.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);
}
var graphics2DGl = graphics2D as Graphics2DOpenGL;
if (graphics2DGl != null)
{
graphics2DGl.PreRender(Color.White);
GL.Begin(BeginMode.Triangles);
int lastFeature = endFeature - 1;
for (int i = startFeature; i < endFeature; i++)
{
RenderFeatureBase feature = all.layers[renderInfo.EndLayerIndex].features[i];
if (feature != null)
{
feature.Render(graphics2DGl, renderInfo, highlightFeature: this.GCodeInspector && i == lastFeature);
}
}
GL.End();
graphics2DGl.PopOrthoProjection();
}
else
{
for (int i = startFeature; i < endFeature; i++)
{
RenderFeatureBase feature = all.layers[renderInfo.EndLayerIndex].features[i];
if (feature != null)
{
feature.Render(graphics2D, renderInfo);
}
}
}
}
}
private GCodeVertexBuffer Create3DDataForLayer(int layerIndex, GCodeRenderInfo renderInfo)
{
var colorVertexData = new VectorPOD<ColorVertexData>();
var vertexIndexArray = new VectorPOD<int>();
var layer = all.layers[layerIndex];
layer.startIndices.Clear();
layer.endIndices.Clear();
for (int i = 0; i < layer.features.Count; i++)
{
layer.startIndices.Add(vertexIndexArray.Count);
RenderFeatureBase feature = layer.features[i];
if (feature != null)
{
// Build the color and index data for the feature
feature.CreateRender3DData(colorVertexData, vertexIndexArray, renderInfo);
}
layer.endIndices.Add(vertexIndexArray.Count);
}
// Construct and return the new VertexBuffer object with all color/index data
return new GCodeVertexBuffer(vertexIndexArray.Array, vertexIndexArray.Count, colorVertexData.Array);
}
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;
}
}
}
}
bool PrepareForGeometryGeneration(GCodeRenderInfo renderInfo)
{
if (renderInfo == null)
{
return false;
}
if (layerVertexBuffer == null)
{
layerVertexBuffer = new List<GCodeVertexBuffer>(gCodeFileToDraw.LayerCount);
for (int layerIndex = 0; layerIndex < gCodeFileToDraw.LayerCount; layerIndex++)
{
layerVertexBuffer.Add(null);
all.layers.Add(new Layer());
}
}
for (int layerIndex = 0; layerIndex < gCodeFileToDraw.LayerCount; layerIndex++)
{
CreateFeaturesForLayerIfRequired(layerIndex);
}
if (lastRenderType != renderInfo.CurrentRenderType)
{
Clear3DGCode();
lastRenderType = renderInfo.CurrentRenderType;
}
return all.layers.Count > 0;
}
public void Render3D(GCodeRenderInfo renderInfo, DrawEventArgs e)
{
if (PrepareForGeometryGeneration(renderInfo))
{
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.Count > i
&& layerVertexBuffer[i] == null)
{
layerVertexBuffer[i] = Create3DDataForLayer(i, renderInfo);
}
}
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++)
{
var layer = all.layers[i];
int featuresOnLayer = layer.features.Count;
if (featuresOnLayer > 1
&& layerVertexBuffer[i] != null)
{
layerVertexBuffer[i].RenderRange(0, layer.endIndices[featuresOnLayer - 1]);
}
}
}
// draw the partial layer of end-1 from startRatio to endRatio
{
int layerIndex = renderInfo.EndLayerIndex - 1;
var layer = all.layers[layerIndex];
int featuresOnLayer = layer.features.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
&& layerVertexBuffer[layerIndex] != null)
{
int ellementCount = layer.endIndices[endFeature - 1] - layer.startIndices[startFeature];
layerVertexBuffer[layerIndex].RenderRange(layer.startIndices[startFeature], ellementCount);
}
}
GL.PopAttrib();
}
}
public AxisAlignedBoundingBox GetAabbOfRender3D(GCodeRenderInfo renderInfo)
{
var box = AxisAlignedBoundingBox.Empty();
if (PrepareForGeometryGeneration(renderInfo))
{
for (int i = renderInfo.EndLayerIndex - 1; i >= renderInfo.StartLayerIndex; i--)
{
if (i < layerVertexBuffer.Count)
{
if (layerVertexBuffer[i] == null)
{
layerVertexBuffer[i] = Create3DDataForLayer(i, renderInfo);
}
box = AxisAlignedBoundingBox.Union(box, layerVertexBuffer[i].BoundingBox);
}
}
}
return box;
}
}
}

View file

@ -0,0 +1,240 @@
/*
Copyright (c) 2018, 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.Agg.UI;
using MatterHackers.RenderOpenGl;
using MatterHackers.RenderOpenGl.OpenGl;
using MatterHackers.VectorMath;
namespace MatterHackers.GCodeVisualizer
{
public class GCodeVertexBuffer : IDisposable
{
private int indexID;
private int indexLength;
private BeginMode pointMode = BeginMode.Triangles;
private bool disposed = false;
private int vertexID;
private int vertexLength;
private ColorVertexData[] colorVertexData;
private AxisAlignedBoundingBox boundingBox = AxisAlignedBoundingBox.Empty();
public AxisAlignedBoundingBox BoundingBox { get { return new AxisAlignedBoundingBox(boundingBox.MinXYZ, boundingBox.MaxXYZ); } }
/// <summary>
/// Create a new VertexBuffer
/// </summary>
/// <param name="indexData">The array containing the vertex indices.</param>
/// <param name="vertexCount">The number of vertices to read from the indexData.</param>
/// <param name="colorData">The array containing the colorData.</param>
public GCodeVertexBuffer(int[] indexData, int vertexCount, ColorVertexData[] colorData)
{
try
{
vertexID = GL.GenBuffer();
indexID = GL.GenBuffer();
SetBufferData(ref indexData, ref colorData);
}
catch
{
var triangleData = new List<ColorVertexData>();
for (int i = 0; i < vertexCount; i += 3)
{
triangleData.Add(colorData[indexData[i]]);
triangleData.Add(colorData[indexData[i + 1]]);
triangleData.Add(colorData[indexData[i + 2]]);
}
this.colorVertexData = triangleData.ToArray();
}
}
private void RenderTriangles(int offset, int count)
{
GL.EnableClientState(ArrayCap.ColorArray);
GL.EnableClientState(ArrayCap.NormalArray);
GL.EnableClientState(ArrayCap.VertexArray);
GL.DisableClientState(ArrayCap.TextureCoordArray);
GL.Disable(EnableCap.Texture2D);
unsafe
{
fixed (ColorVertexData* pFixedColorData = colorVertexData)
{
byte* pColorData = (byte*)(pFixedColorData + offset);
byte* pNormalData = pColorData + 4;
byte* pPosition = pNormalData + 12;
GL.VertexPointer(3, VertexPointerType.Float, ColorVertexData.Stride, new IntPtr(pPosition));
GL.NormalPointer(NormalPointerType.Float, ColorVertexData.Stride, new IntPtr(pNormalData));
GL.ColorPointer(4, ColorPointerType.UnsignedByte, ColorVertexData.Stride, new IntPtr(pColorData));
GL.DrawArrays(BeginMode.Triangles, ColorVertexData.Stride, Math.Min(colorVertexData.Length, count));
}
}
GL.DisableClientState(ArrayCap.NormalArray);
GL.DisableClientState(ArrayCap.VertexArray);
GL.DisableClientState(ArrayCap.ColorArray);
GL.ColorPointer(4, ColorPointerType.UnsignedByte, 0, new IntPtr(0));
GL.NormalPointer(NormalPointerType.Float, 0, new IntPtr(0));
GL.VertexPointer(3, VertexPointerType.Float, 0, new IntPtr(0));
}
private void SetBufferData(ref int[] indexData, ref ColorVertexData[] colorData)
{
// Set vertex data
vertexLength = colorData.Length;
if (vertexLength > 0)
{
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexID);
unsafe
{
fixed (ColorVertexData* dataPointer = colorData)
{
GL.BufferData(BufferTarget.ArrayBuffer, colorData.Length * ColorVertexData.Stride, (IntPtr)dataPointer, BufferUsageHint.StaticDraw);
}
}
}
// Set index data
indexLength = indexData.Length;
if (indexLength > 0)
{
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexID);
unsafe
{
fixed (int* dataPointer = indexData)
{
GL.BufferData(BufferTarget.ElementArrayBuffer, indexData.Length * sizeof(int), (IntPtr)dataPointer, BufferUsageHint.StaticDraw);
}
}
}
boundingBox = AxisAlignedBoundingBox.Empty();
foreach (int i in indexData)
{
var v = colorData[i];
boundingBox.ExpandToInclude(new Vector3Float(v.positionX, v.positionY, v.positionZ));
}
}
public void RenderRange(int offset, int count)
{
if (vertexID == 0)
{
// not allocated don't render
RenderTriangles(offset, count);
}
else
{
RenderBufferData(offset, count);
}
}
private void RenderBufferData(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, vertexID);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexID);
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));
// ** Draw **
GL.DrawRangeElements(
pointMode,
0,
indexLength,
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);
}
protected virtual void Dispose(bool disposing)
{
if (vertexID == 0)
{
// not allocated don't dispose
return;
}
// release unmanaged resources
if (!disposed)
{
UiThread.RunOnIdle(() =>
{
GL.DeleteBuffer(vertexID);
GL.DeleteBuffer(indexID);
});
disposed = true;
}
if (disposing)
{
// release other Managed objects
// if (resource!= null) resource.Dispose();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~GCodeVertexBuffer()
{
Dispose(false);
}
}
}

View file

@ -0,0 +1,197 @@
/*
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 toolIndex;
/// <summary>
/// The actual gcode line in the source gcode file
/// </summary>
public int InstructionIndex { get; private set; }
public static Color HighlightColor { get; set; } = new Color("#D0F476");
public static Color StartColor { get; set; } = Color.Red;
public static Color EndColor { get; set; } = new Color("#008000");
public abstract void Render(Graphics2D graphics2D, GCodeRenderInfo renderInfo, bool highlightFeature = false);
public abstract void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, GCodeRenderInfo renderInfo);
protected RenderFeatureBase(int instructionIndex, int toolIndex)
{
this.toolIndex = toolIndex;
this.InstructionIndex = instructionIndex;
}
static public void CreateCylinder(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, Vector3 startPos, Vector3 endPos, double radius, int steps, Color color, double layerHeight)
{
var direction = endPos - startPos;
var directionNormal = direction.GetNormal();
var 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;
// Adjust start/end positions to be centered on Z for the given layer height
startPos.Z -= halfHeight;
endPos.Z -= halfHeight;
var scale = new Vector3(xScale, xScale, zScale);
var rotateAngle = Vector3Ex.Cross(startSweepDirection, direction);
var startCapStartNormal = Vector3Ex.Transform(startSweepDirection, Matrix4X4.CreateRotation(rotateAngle, MathHelper.Tau / 8));
var startCapEndNormal = Vector3Ex.Transform(startSweepDirection, Matrix4X4.CreateRotation(-rotateAngle, MathHelper.Tau / 8));
for (int i = 0; i < steps; i++)
{
var rotationMatrix = Matrix4X4.CreateRotation(direction, MathHelper.Tau / (steps * 2) + MathHelper.Tau / (steps) * i);
// create tube ends verts
var tubeNormal = Vector3Ex.Transform(startSweepDirection, rotationMatrix);
var offset = Vector3Ex.Transform(startSweepDirection * radius, rotationMatrix) * scale;
var tubeStart = startPos + offset;
tubeStartIndices[i] = colorVertexData.Count;
colorVertexData.Add(new ColorVertexData(tubeStart, tubeNormal, color));
var tubeEnd = endPos + offset;
tubeEndIndices[i] = colorVertexData.Count;
colorVertexData.Add(new ColorVertexData(tubeEnd, tubeNormal, color));
// create cap verts
var capStartNormal = Vector3Ex.Transform(startCapStartNormal, rotationMatrix);
capStartNormal = (capStartNormal * scale).GetNormal();
var capStartOffset = capStartNormal * radius * scale;
var capStart = startPos + capStartOffset;
capStartIndices[i] = colorVertexData.Count;
colorVertexData.Add(new ColorVertexData(capStart, capStartNormal, color));
var capEndNormal = Vector3Ex.Transform(startCapEndNormal, rotationMatrix);
capEndNormal = (capEndNormal * scale).GetNormal();
var capEndOffset = capEndNormal * radius * scale;
var capEnd = endPos + capEndOffset;
capEndIndices[i] = colorVertexData.Count;
colorVertexData.Add(new ColorVertexData(capEnd, capEndNormal, color));
}
int tipStartIndex = colorVertexData.Count;
var 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, Color color)
{
var direction = endPos - startPos;
var directionNormal = direction.GetNormal();
var startSweepDirection = Vector3.GetPerpendicular(startPos, endPos).GetNormal();
int[] tubeStartIndices = new int[steps];
for (int i = 0; i < steps; i++)
{
var rotationMatrix = Matrix4X4.CreateRotation(direction, MathHelper.Tau / (steps * 2) + MathHelper.Tau / (steps) * i);
// create tube ends verts
var tubeNormal = Vector3Ex.Transform(startSweepDirection, rotationMatrix);
var offset = Vector3Ex.Transform(startSweepDirection * radius, rotationMatrix);
var tubeStart = startPos + offset;
tubeStartIndices[i] = colorVertexData.Count;
colorVertexData.Add(new ColorVertexData(tubeStart, tubeNormal, color));
}
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);
}
}
}
}

View file

@ -0,0 +1,178 @@
/*
Copyright (c) 2019, 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 MatterHackers.Agg;
using MatterHackers.Agg.VertexSource;
using MatterHackers.RenderOpenGl;
using MatterHackers.VectorMath;
namespace MatterHackers.GCodeVisualizer
{
public class RenderFeatureExtrusion : RenderFeatureTravel
{
private float extrusionVolumeMm3;
private float layerHeight;
private Color color;
private Color gray;
public RenderFeatureExtrusion(int instructionIndex, Vector3 start, Vector3 end, int toolIndex, double travelSpeed, double totalExtrusionMm, double filamentDiameterMm, double layerHeight, Color color, Color gray)
: base(instructionIndex, start, end, toolIndex, travelSpeed, false)
{
this.color = color;
this.gray = gray;
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;
}
}
else
{
// TODO: adjust line render to reduce the height of the line as well
//
// Force line width to 0.1 when SimulateExtrusion is disabled, to produce a visualization of the toolpath rather than the extrudate
width = 0.1;
}
return width;
}
public override void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, GCodeRenderInfo renderInfo)
{
if ((renderInfo.CurrentRenderType & RenderType.Extrusions) == RenderType.Extrusions)
{
double radius = GetRadius(renderInfo.CurrentRenderType);
Color lineColor;
if (renderInfo.CurrentRenderType.HasFlag(RenderType.SpeedColors))
{
lineColor = color;
}
else if (renderInfo.CurrentRenderType.HasFlag(RenderType.GrayColors))
{
lineColor = this.gray;
}
else
{
lineColor = renderInfo.GetMaterialColor(toolIndex);
}
CreateCylinder(colorVertexData, indexData, new Vector3(start), new Vector3(end), radius, 6, lineColor, layerHeight);
}
}
public override void Render(Graphics2D graphics2D, GCodeRenderInfo renderInfo, bool highlightFeature = false)
{
if (renderInfo.CurrentRenderType.HasFlag(RenderType.Extrusions))
{
double extrusionLineWidths = GetExtrusionWidth(renderInfo.CurrentRenderType) * 2 * renderInfo.LayerScale;
Color extrusionColor = Color.Black;
if (highlightFeature)
{
extrusionColor = RenderFeatureBase.HighlightColor;
}
else if (renderInfo.CurrentRenderType.HasFlag(RenderType.SpeedColors))
{
extrusionColor = color;
}
else if (renderInfo.CurrentRenderType.HasFlag(RenderType.GrayColors))
{
extrusionColor = Color.Gray;
}
else
{
extrusionColor = renderInfo.GetMaterialColor(toolIndex);
}
if (renderInfo.CurrentRenderType.HasFlag(RenderType.TransparentExtrusion))
{
extrusionColor = new Color(extrusionColor, 200);
}
if (graphics2D is Graphics2DOpenGL graphics2DGl)
{
// render using opengl
var startPoint = new Vector2(start.X, start.Y);
renderInfo.Transform.transform(ref startPoint);
var endPoint = new Vector2(end.X, end.Y);
renderInfo.Transform.transform(ref endPoint);
var eWidth = extrusionLineWidths / 2;
graphics2DGl.DrawAALineRounded(startPoint, endPoint, eWidth, extrusionColor);
if (highlightFeature)
{
Render3DStartEndMarkers(graphics2DGl, eWidth / 2, startPoint, endPoint);
}
}
else
{
// render using agg
var pathStorage = new VertexStorage();
var transformedPathStorage = new VertexSourceApplyTransform(pathStorage, renderInfo.Transform);
var stroke = new Stroke(transformedPathStorage, extrusionLineWidths / 2)
{
LineCap = LineCap.Round,
LineJoin = LineJoin.Round
};
pathStorage.Add(start.X, start.Y, FlagsAndCommand.MoveTo);
pathStorage.Add(end.X, end.Y, FlagsAndCommand.LineTo);
graphics2D.Render(stroke, extrusionColor);
}
}
}
}
}

View file

@ -0,0 +1,132 @@
/*
Copyright (c) 2019, 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 MatterHackers.Agg;
using MatterHackers.Agg.VertexSource;
using MatterHackers.RenderOpenGl;
using MatterHackers.VectorMath;
namespace MatterHackers.GCodeVisualizer
{
public class RenderFeatureRetract : RenderFeatureBase
{
public static double RetractionDrawRadius = 1;
private float extrusionAmount;
private float mmPerSecond;
private Vector3Float position;
public RenderFeatureRetract(int instructionIndex, Vector3 position, double extrusionAmount, int extruderIndex, double mmPerSecond)
: base(instructionIndex, 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)
{
var position = new Vector3(this.position);
// retract and unretract are the extruder color
Color color = renderInfo.GetMaterialColor(toolIndex);
// except for extruder 0 where they are the red and blue we are familiar with
if (toolIndex == 0)
{
if (extrusionAmount > 0)
{
color = Color.Blue;
}
else
{
color = Color.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, bool highlightFeature = false)
{
if ((renderInfo.CurrentRenderType & RenderType.Retractions) == RenderType.Retractions)
{
double radius = Radius(renderInfo.LayerScale);
var position = new Vector2(this.position.X, this.position.Y);
renderInfo.Transform.transform(ref position);
var retractionColor = new Color(Color.Red, 200);
if (highlightFeature)
{
retractionColor = RenderFeatureBase.HighlightColor;
}
else if (extrusionAmount > 0)
{
// unretraction
retractionColor = Color.Blue.WithAlpha(120);
}
if (graphics2D is Graphics2DOpenGL graphics2DGl)
{
// render using opengl
graphics2DGl.DrawAACircle(position, radius, retractionColor);
}
else
{
// render using agg
graphics2D.Render(
new Ellipse(position, radius),
retractionColor);
}
}
}
}
}

View file

@ -0,0 +1,127 @@
/*
Copyright (c) 2019, 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 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;
private bool retractionTravel;
public Vector3Float Start => start;
public Vector3Float End => end;
public RenderFeatureTravel(int instructionIndex, Vector3 start, Vector3 end, int toolIndex, double travelSpeed, bool retractionTravel)
: base(instructionIndex, toolIndex)
{
this.toolIndex = toolIndex;
this.start = new Vector3Float(start);
this.end = new Vector3Float(end);
this.travelSpeed = (float)travelSpeed;
this.retractionTravel = retractionTravel;
}
public override void CreateRender3DData(VectorPOD<ColorVertexData> colorVertexData, VectorPOD<int> indexData, GCodeRenderInfo renderInfo)
{
if ((renderInfo.CurrentRenderType & RenderType.Moves) == RenderType.Moves)
{
CreateCylinder(colorVertexData, indexData, new Vector3(start), new Vector3(end), .1, 6, retractionTravel ? GCodeRenderer.RetractionColor : GCodeRenderer.TravelColor, .2);
}
}
protected void Render3DStartEndMarkers(Graphics2DOpenGL graphics2DGl, double radius, Vector2 startPoint, Vector2 endPoint)
{
graphics2DGl.DrawAACircle(startPoint, radius, RenderFeatureBase.StartColor);
graphics2DGl.DrawAACircle(endPoint, radius, RenderFeatureBase.EndColor);
}
public override void Render(Graphics2D graphics2D, GCodeRenderInfo renderInfo, bool highlightFeature = false)
{
if ((renderInfo.CurrentRenderType & RenderType.Moves) == RenderType.Moves)
{
double movementLineWidth = 0.2 * renderInfo.LayerScale;
Color movementColor = (highlightFeature) ? RenderFeatureBase.HighlightColor : new Color(10, 190, 15);
if (graphics2D is Graphics2DOpenGL graphics2DGl)
{
// render using opengl
var startPoint = new Vector2(start.X, start.Y);
renderInfo.Transform.transform(ref startPoint);
var endPoint = new Vector2(end.X, end.Y);
renderInfo.Transform.transform(ref endPoint);
if (retractionTravel)
{
movementColor = GCodeRenderer.RetractionColor;
}
if (renderInfo.CurrentRenderType.HasFlag(RenderType.TransparentExtrusion))
{
movementColor = movementColor.WithAlpha(120);
}
graphics2DGl.DrawAALineRounded(startPoint, endPoint, movementLineWidth, movementColor);
}
else
{
// render using agg
var pathStorage = new VertexStorage();
var transformedPathStorage = new VertexSourceApplyTransform(pathStorage, renderInfo.Transform);
var stroke = new Stroke(transformedPathStorage, movementLineWidth)
{
LineCap = LineCap.Round,
LineJoin = LineJoin.Round
};
pathStorage.Add(start.X, start.Y, FlagsAndCommand.MoveTo);
if (end.X != start.X || end.Y != start.Y)
{
pathStorage.Add(end.X, end.Y, FlagsAndCommand.LineTo);
}
else
{
pathStorage.Add(end.X + .01, end.Y, FlagsAndCommand.LineTo);
}
graphics2D.Render(stroke, movementColor);
}
}
}
}
}

View file

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Company>MatterHackers Inc.</Company>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ReleaseVersion>2.20.12</ReleaseVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MatterControl.Printing\MatterControl.Printing.csproj">
</ProjectReference>
<ProjectReference Include="..\Submodules\agg-sharp\agg\Agg.csproj">
</ProjectReference>
<ProjectReference Include="..\Submodules\agg-sharp\Gui\Gui.csproj">
</ProjectReference>
<ProjectReference Include="..\Submodules\agg-sharp\RenderOpenGl\RenderOpenGl.csproj">
</ProjectReference>
<ProjectReference Include="..\Submodules\agg-sharp\VectorMath\VectorMath.csproj">
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Update="StyleCop.Analyzers" Version="1.1.118" />
</ItemGroup>
</Project>