commit adecdc13e52d0794200ba8c0d4367f12fe3afdbf Author: AJ Date: Fri Aug 31 07:25:48 2018 -0400 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0570523 --- /dev/null +++ b/.gitignore @@ -0,0 +1,196 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# If using the old MSBuild-Integrated Package Restore, uncomment this: +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +#ignore thumbnails created by windows +Thumbs.db +#Ignore files build by Visual Studio +*.exe +*.bak +*.cache +[Bb]in +[Dd]ebug*/ +*.lib +obj/ +[Rr]elease*/ +[Tt]est[Rr]esult* diff --git a/PepLib.Dxf/DxfConverter.cs b/PepLib.Dxf/DxfConverter.cs new file mode 100644 index 0000000..6737ca8 --- /dev/null +++ b/PepLib.Dxf/DxfConverter.cs @@ -0,0 +1,226 @@ +using PepLib.Codes; +using netDxf; +using netDxf.Entities; +using netDxf.Tables; +using System; +using PepProgram = PepLib.Program; + +namespace PepLib.Dxf +{ + public class DxfConverter + { + private const double RadToDeg = 180.0 / Math.PI; + + private DxfDocument doc; + private Vector2 curpos; + private ProgrammingMode mode; + private readonly Layer cutLayer; + private readonly Layer rapidLayer; + private readonly Layer plateLayer; + + public DxfConverter() + { + doc = new DxfDocument(); + + cutLayer = new Layer("Cut"); + cutLayer.Color = AciColor.Red; + + rapidLayer = new Layer("Rapid"); + rapidLayer.Color = AciColor.Blue; + rapidLayer.LineType = LineType.Dashed; + + plateLayer = new Layer("Plate"); + plateLayer.Color = AciColor.Cyan; + } + + public DxfDocument ConvertLoop(Loop loop) + { + doc = new DxfDocument(); + AddProgram(loop); + return doc; + } + + public DxfDocument ConvertPlate(Plate plate) + { + doc = new DxfDocument(); + AddPlateOutline(plate); + + foreach (var part in plate.Parts) + { + curpos = part.Location.ToDxfVector(); + AddProgram(part.Program); + } + + return doc; + } + + public DxfDocument ConvertProgram(PepProgram program) + { + doc = new DxfDocument(); + AddProgram(program); + return doc; + } + + private void AddPlateOutline(Plate plate) + { + Vector2 pt1; + Vector2 pt2; + Vector2 pt3; + Vector2 pt4; + + switch (plate.Quadrant) + { + case 1: + pt1 = new Vector2(0, 0); + pt2 = new Vector2(0, plate.Size.Height); + pt3 = new Vector2(plate.Size.Width, plate.Size.Height); + pt4 = new Vector2(plate.Size.Width, 0); + break; + + case 2: + pt1 = new Vector2(0, 0); + pt2 = new Vector2(0, plate.Size.Height); + pt3 = new Vector2(-plate.Size.Width, plate.Size.Height); + pt4 = new Vector2(-plate.Size.Width, 0); + break; + + case 3: + pt1 = new Vector2(0, 0); + pt2 = new Vector2(0, -plate.Size.Height); + pt3 = new Vector2(-plate.Size.Width, -plate.Size.Height); + pt4 = new Vector2(-plate.Size.Width, 0); + break; + + case 4: + pt1 = new Vector2(0, 0); + pt2 = new Vector2(0, -plate.Size.Height); + pt3 = new Vector2(plate.Size.Width, -plate.Size.Height); + pt4 = new Vector2(plate.Size.Width, 0); + break; + + default: + return; + } + + doc.AddEntity(new Line(pt1, pt2) { Layer = plateLayer }); + doc.AddEntity(new Line(pt2, pt3) { Layer = plateLayer }); + doc.AddEntity(new Line(pt3, pt4) { Layer = plateLayer }); + doc.AddEntity(new Line(pt4, pt1) { Layer = plateLayer }); + } + + private void AddProgram(PepProgram program) + { + mode = program.Mode; + + foreach (var code in program) + { + switch (code.CodeType()) + { + case CodeType.CircularMove: + var arc = (CircularMove)code; + AddCircularMove(arc); + break; + + case CodeType.LinearMove: + var line = (LinearMove)code; + AddLinearMove(line); + break; + + case CodeType.RapidMove: + var rapid = (RapidMove)code; + AddRapidMove(rapid); + break; + + case CodeType.SubProgramCall: + var tmpmode = mode; + var subpgm = (PepLib.Codes.SubProgramCall)code; + AddProgram(subpgm.Loop); + mode = tmpmode; + break; + } + } + } + + private void AddLinearMove(LinearMove line) + { + var pt = line.EndPoint.ToDxfVector(); + + if (mode == ProgrammingMode.Incremental) + pt += curpos; + + var ln = new Line(curpos, pt); + ln.Layer = cutLayer; + doc.AddEntity(ln); + curpos = pt; + } + + private void AddRapidMove(RapidMove rapid) + { + var pt = rapid.EndPoint.ToDxfVector(); + + if (mode == ProgrammingMode.Incremental) + pt += curpos; + + var ln = new Line(curpos, pt); + ln.Layer = rapidLayer; + doc.AddEntity(ln); + curpos = pt; + } + + private void AddCircularMove(CircularMove arc) + { + var center = arc.CenterPoint.ToDxfVector(); + var endpt = arc.EndPoint.ToDxfVector(); + + if (mode == ProgrammingMode.Incremental) + { + endpt += curpos; + center += curpos; + } + + // start angle in radians + var startAngle = Math.Atan2( + curpos.Y - center.Y, + curpos.X - center.X); + + // end angle in radians + var endAngle = Math.Atan2( + endpt.Y - center.Y, + endpt.X - center.X); + + // convert the angles to degrees + startAngle *= RadToDeg; + endAngle *= RadToDeg; + + if (arc.Rotation == PepLib.RotationType.CW) + Swap(ref startAngle, ref endAngle); + + var dx = endpt.X - center.X; + var dy = endpt.Y - center.Y; + + var radius = Math.Sqrt(dx * dx + dy * dy); + + if (startAngle.IsEqualTo(endAngle)) + { + var circle = new Circle(center, radius); + circle.Layer = cutLayer; + doc.AddEntity(circle); + } + else + { + var arc2 = new Arc(center, radius, startAngle, endAngle); + arc2.Layer = cutLayer; + doc.AddEntity(arc2); + } + + curpos = endpt; + } + + private static void Swap(ref T a, ref T b) + { + T c = a; + a = b; + b = c; + } + } +} diff --git a/PepLib.Dxf/DxfExtensions.cs b/PepLib.Dxf/DxfExtensions.cs new file mode 100644 index 0000000..8328b1a --- /dev/null +++ b/PepLib.Dxf/DxfExtensions.cs @@ -0,0 +1,13 @@ +using DxfVector = netDxf.Vector2; +using PepVector = PepLib.Vector; + +namespace PepLib.Dxf +{ + internal static class DxfExtensions + { + public static PepVector ToPepVector(this DxfVector v) + { + return new PepVector(v.X, v.Y); + } + } +} diff --git a/PepLib.Dxf/PepExtensions.cs b/PepLib.Dxf/PepExtensions.cs new file mode 100644 index 0000000..2b3d2e4 --- /dev/null +++ b/PepLib.Dxf/PepExtensions.cs @@ -0,0 +1,13 @@ +using DxfVector = netDxf.Vector2; +using PepVector = PepLib.Vector; + +namespace PepLib.Dxf +{ + internal static class PepExtensions + { + public static DxfVector ToDxfVector(this PepVector v) + { + return new DxfVector(v.X, v.Y); + } + } +} diff --git a/PepLib.Dxf/PepLib.Dxf.csproj b/PepLib.Dxf/PepLib.Dxf.csproj new file mode 100644 index 0000000..1412bcb --- /dev/null +++ b/PepLib.Dxf/PepLib.Dxf.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {E15A7403-B16D-4D11-A061-2F5E98DF36B0} + Library + Properties + PepLib.Dxf + PepLib.Dxf + v4.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\lib\netDxf.dll + + + + + + + + + + + + {22360453-B878-49FA-A5DC-0D9C577DE902} + PepLib + + + + + \ No newline at end of file diff --git a/PepLib.Dxf/Properties/AssemblyInfo.cs b/PepLib.Dxf/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0c10b9d --- /dev/null +++ b/PepLib.Dxf/Properties/AssemblyInfo.cs @@ -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("PepLib.Dxf")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PepLib.Dxf")] +[assembly: AssemblyCopyright("Copyright © AJ Isaacs 2014")] +[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("5f159892-11c1-46f4-94be-ae9a7e81c1bc")] + +// 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")] diff --git a/PepLib.Dxf/lib/netDxf.dll b/PepLib.Dxf/lib/netDxf.dll new file mode 100644 index 0000000..07d43fd Binary files /dev/null and b/PepLib.Dxf/lib/netDxf.dll differ diff --git a/PepLib.UI/App.config b/PepLib.UI/App.config new file mode 100644 index 0000000..74ade9d --- /dev/null +++ b/PepLib.UI/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/PepLib.UI/LayoutView.cs b/PepLib.UI/LayoutView.cs new file mode 100644 index 0000000..b47e222 --- /dev/null +++ b/PepLib.UI/LayoutView.cs @@ -0,0 +1,895 @@ +using PepLib; +using PepLib.Codes; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace Pep.Controls +{ + public class LayoutView : Control + { + private float scale; + + private const int BorderWidth = 50; + private const float ZoomInFactor = 1.3f; + private const float ZoomOutFactor = 1.0f / ZoomInFactor; + + private bool pathsNeedUpdated; + private GraphicsPath[] paths; + + private PointF origin; + private Point lastPoint; + + private readonly Brush layoutFillBrush; + private readonly Brush loopFillBrush; + + private readonly Pen layoutBorderPen; + private readonly Pen loopBorderPen; + private readonly Pen rapidPen; + private readonly Pen originPen; + private readonly Pen edgeSpacingPen; + private ToolTip tooltip; + private bool isPanning; + + private string selectedDrawing; + + private readonly Font loopIdFont; + private Vector curpos; + private ProgrammingMode mode; + + public Vector CurrentPoint { get; private set; } + + public Plate Plate { get; set; } + + public LayoutView() + { + paths = new GraphicsPath[0]; + + layoutFillBrush = new SolidBrush(Color.White); + loopFillBrush = new SolidBrush(Color.FromArgb(130, 204, 130)); + loopFillBrush = new SolidBrush(Color.FromArgb(130, 204, 130)); + + tooltip = new ToolTip(); + tooltip.UseAnimation = false; + tooltip.UseFading = false; + + layoutBorderPen = new Pen(Color.Gray); + loopBorderPen = new Pen(Color.Green); + rapidPen = new Pen(Color.DodgerBlue) { DashPattern = new float[] { 10, 10 } }; + originPen = new Pen(Color.Gray); + edgeSpacingPen = new Pen(Color.FromArgb(180, 180, 180)) { DashPattern = new float[] { 3, 3 } }; + + loopIdFont = new Font(DefaultFont, FontStyle.Bold | FontStyle.Underline); + + scale = 1.0f; + origin = new PointF(); + + SetStyle( + ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer | + ControlStyles.UserPaint, true); + + DrawRapid = false; + DrawBounds = false; + FillParts = true; + Plate = new Plate(60, 120); + + Cursor = Cursors.Cross; + + pathsNeedUpdated = true; + } + + public bool DrawRapid { get; set; } + + public bool DrawBounds { get; set; } + + public bool FillParts { get; set; } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + ZoomToFit(); + } + + protected override void OnMouseWheel(MouseEventArgs e) + { + base.OnMouseWheel(e); + + float multiplier = Math.Abs(e.Delta / 120.0f); + + if (e.Delta > 0) + ZoomToPoint(e.Location, (float)Math.Pow(ZoomInFactor, multiplier)); + else + ZoomToPoint(e.Location, (float)Math.Pow(ZoomOutFactor, multiplier)); + + pathsNeedUpdated = true; + Invalidate(); + } + + protected override void OnMouseMove(MouseEventArgs e) + { + if (e.Location == lastPoint) + return; + + CurrentPoint = PointControlToWorld(e.Location); + + if (e.Button == MouseButtons.Middle) + { + var diffx = e.X - lastPoint.X; + var diffy = e.Y - lastPoint.Y; + + origin.X += diffx; + origin.Y += diffy; + + Invalidate(); + } + + lastPoint = e.Location; + + ShowTooltipForPartAtLocation(e.Location); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + if (e.Button == MouseButtons.Middle) + isPanning = true; + } + + protected override void OnMouseUp(MouseEventArgs e) + { + if (e.Button == MouseButtons.Middle) + isPanning = false; + } + + protected override void OnMouseClick(MouseEventArgs e) + { + base.OnMouseClick(e); + + Focus(); + + if (e.Button == MouseButtons.Left) + { + var part = GetPartAtPoint(e.Location); + + selectedDrawing = part?.DrawingName; + Invalidate(); + } + } + + protected override void OnMouseDoubleClick(MouseEventArgs e) + { + base.OnMouseDoubleClick(e); + + if (e.Button == MouseButtons.Middle) + ZoomToFit(); + } + + protected override bool ProcessDialogKey(Keys keyData) + { + OnKeyDown(new KeyEventArgs(keyData)); + return base.ProcessDialogKey(keyData); + } + + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + + if (e.KeyCode == Keys.Escape) + { + selectedDrawing = null; + Invalidate(); + } + } + + protected override void OnPaint(PaintEventArgs e) + { + curpos = new Vector(); + e.Graphics.TranslateTransform(origin.X, origin.Y); + DrawPlate(e.Graphics); + DrawOrigin(e.Graphics); + } + + private void DrawPlateInfo(Graphics g) + { + var font = new Font(Font.FontFamily, 10, FontStyle.Bold | FontStyle.Italic); + + var location = new PointF(5, -LengthWorldToGui(Plate.Size.Height) - font.GetHeight()); + + g.DrawString(Plate.Size.ToString() + ", Qty: " + Plate.Duplicates, font, Brushes.Gray, location); + } + + private void ShowTooltipForPartAtLocation(Point pt) + { + if (isPanning) + { + tooltip.Hide(this); + return; + } + + var part = GetPartAtPoint(pt); + + if (part == null) + { + tooltip.Hide(this); + return; + } + + tooltip.ToolTipTitle = part.DrawingName; + + var sb = new StringBuilder(); + sb.AppendLine(string.Format("Qty on Sheet:\t{0}", Plate.GetQtyNested(part.DrawingName))); + sb.AppendLine(string.Format("Loop Name:\t{0}", part.Name)); + sb.AppendLine(string.Format("Location:\t({0}, {1})", part.Location.X, part.Location.Y)); + sb.AppendLine(string.Format("Rotation:\t{0}", AngleConverter.ToDegrees(part.Rotation))); + tooltip.Show(sb.ToString(), this, pt.X + 2, pt.Y + 2); + } + + private void DrawOrigin(Graphics g) + { + g.SmoothingMode = SmoothingMode.AntiAlias; + + var w = 7.0f; + var hw = w / 2.0f; + + var rect = new RectangleF( + -hw, + -hw, + w, w); + + g.FillEllipse(Brushes.Orange, rect); + g.DrawEllipse(Pens.Red, rect); + + g.SmoothingMode = SmoothingMode.HighSpeed; + } + + private void DrawPlate(Graphics g) + { + Debug.WriteLine(Plate.Size.ToString()); + var plateRect = new RectangleF + { + Width = LengthWorldToGui(Plate.Size.Width), + Height = LengthWorldToGui(Plate.Size.Height) + }; + + var edgeSpacingRect = new RectangleF + { + Width = LengthWorldToGui(Plate.Size.Width - Plate.EdgeSpacing.Left - Plate.EdgeSpacing.Right), + Height = LengthWorldToGui(Plate.Size.Height - Plate.EdgeSpacing.Top - Plate.EdgeSpacing.Bottom) + }; + + switch (Plate.Quadrant) + { + case 1: + plateRect.Location = PointWorldToGraph(0, 0); + edgeSpacingRect.Location = PointWorldToGraph( + Plate.EdgeSpacing.Left, + Plate.EdgeSpacing.Bottom); + break; + + case 2: + plateRect.Location = PointWorldToGraph(-Plate.Size.Width, 0); + edgeSpacingRect.Location = PointWorldToGraph( + Plate.EdgeSpacing.Left - Plate.Size.Width, + Plate.EdgeSpacing.Bottom); + break; + + case 3: + plateRect.Location = PointWorldToGraph(-Plate.Size.Width, -Plate.Size.Height); + edgeSpacingRect.Location = PointWorldToGraph( + Plate.EdgeSpacing.Left - Plate.Size.Width, + Plate.EdgeSpacing.Bottom - Plate.Size.Height); + break; + + case 4: + plateRect.Location = PointWorldToGraph(0, -Plate.Size.Height); + edgeSpacingRect.Location = PointWorldToGraph( + Plate.EdgeSpacing.Left, + Plate.EdgeSpacing.Bottom - Plate.Size.Height); + break; + + default: + return; + } + + plateRect.Y -= plateRect.Height; + edgeSpacingRect.Y -= edgeSpacingRect.Height; + + g.FillRectangle(layoutFillBrush, plateRect); + + var viewBounds = new RectangleF(-origin.X, -origin.Y, Width, Height); + + if (!edgeSpacingRect.Contains(viewBounds)) + { + g.DrawRectangle(edgeSpacingPen, + edgeSpacingRect.X, + edgeSpacingRect.Y, + edgeSpacingRect.Width, + edgeSpacingRect.Height); + } + + g.DrawRectangle(layoutBorderPen, + plateRect.X, + plateRect.Y, + plateRect.Width, + plateRect.Height); + + DrawParts(g); + DrawPlateInfo(g); + } + + private void DrawParts(Graphics g) + { + if (pathsNeedUpdated || paths.Length != Plate.Parts.Count) + UpdatePaths(); + + var viewBounds = new RectangleF(-origin.X, -origin.Y, Width, Height); + + for (int i = 0; i < Plate.Parts.Count; ++i) + { + var part = Plate.Parts[i]; + var path = paths[i]; + var pathBounds = path.GetBounds(); + + if (!pathBounds.IntersectsWith(viewBounds)) + continue; + + if (DrawBounds) + DrawBox(g, part.BoundingBox); + + if (part.DrawingName == selectedDrawing) + { + var brush = new SolidBrush(Color.Aqua); + var pen = new Pen(Color.Blue); + + if (FillParts) + g.FillPath(brush, path); + + g.DrawPath(pen, path); + } + else + { + if (FillParts) + g.FillPath(loopFillBrush, path); + + g.DrawPath(loopBorderPen, path); + } + + var pt = PointWorldToGraph(part.AbsoluteReferencePoint); + + g.DrawString((i + 1).ToString(), loopIdFont, Brushes.Black, pt.X, pt.Y); + } + + if (DrawRapid) + DrawRapids(g); + } + + private void DrawProgram(GraphicsPath g, PepLib.Program pgm) + { + mode = pgm.Mode; + + foreach (var code in pgm) + { + switch (code.CodeType()) + { + case CodeType.CircularMove: + { + var arc = (CircularMove)code; + DrawArc(g, arc); + break; + } + + case CodeType.LinearMove: + { + var line = (LinearMove)code; + DrawLine(g, line); + break; + } + + case CodeType.RapidMove: + { + var rapid = (RapidMove)code; + DrawLine(g, rapid); + break; + } + + case CodeType.SubProgramCall: + { + var tmpmode = mode; + var subpgm = (SubProgramCall)code; + + if (subpgm.Loop != null) + { + g.StartFigure(); + DrawProgram(g, subpgm.Loop); + } + + mode = tmpmode; + break; + } + } + } + } + + private void DrawLine(GraphicsPath g, LinearMove line) + { + var pt = line.EndPoint; + + if (mode == ProgrammingMode.Incremental) + pt += curpos; + + var pt1 = PointWorldToGraph(curpos); + var pt2 = PointWorldToGraph(pt); + + g.AddLine(pt1, pt2); + + if (line.Type == EntityType.ExternalLeadin || line.Type == EntityType.ExternalLeadout || + line.Type == EntityType.InternalLeadin || line.Type == EntityType.InternalLeadout) + { + g.CloseFigure(); + } + + curpos = pt; + } + + private void DrawLine(GraphicsPath g, RapidMove line) + { + var pt = line.EndPoint; + + if (mode == ProgrammingMode.Incremental) + pt += curpos; + + g.CloseFigure(); + + curpos = pt; + } + + private void DrawArc(GraphicsPath g, CircularMove arc) + { + var endpt = arc.EndPoint; + var center = arc.CenterPoint; + + if (mode == ProgrammingMode.Incremental) + { + endpt += curpos; + center += curpos; + } + + // start angle in degrees + var startAngle = AngleConverter.ToDegrees(Math.Atan2( + curpos.Y - center.Y, + curpos.X - center.X)); + + // end angle in degrees + var endAngle = AngleConverter.ToDegrees(Math.Atan2( + endpt.Y - center.Y, + endpt.X - center.X)); + + endAngle = NormalizeAngle(endAngle); + startAngle = NormalizeAngle(startAngle); + + if (arc.Rotation == RotationType.CCW && endAngle < startAngle) + endAngle += 360.0; + else if (arc.Rotation == RotationType.CW && startAngle < endAngle) + startAngle += 360.0; + + var dx = endpt.X - center.X; + var dy = endpt.Y - center.Y; + + var radius = Math.Sqrt(dx * dx + dy * dy); + + var pt = PointWorldToGraph(center.X - radius, center.Y + radius); + var size = LengthWorldToGui(radius * 2.0); + + if (startAngle.IsEqualTo(endAngle)) + { + g.AddEllipse(pt.X, pt.Y, size, size); + } + else + { + var sweepAngle = -(endAngle - startAngle); + + g.AddArc(pt.X, pt.Y, size, size, + (float)-startAngle, (float)sweepAngle); + + if (arc.Type == EntityType.ExternalLeadin || arc.Type == EntityType.ExternalLeadout || + arc.Type == EntityType.InternalLeadin || arc.Type == EntityType.InternalLeadout) + { + // hack to not have the graphics path fill the leadin/leadout area. + g.AddArc(pt.X, pt.Y, size, size, (float)(-startAngle + sweepAngle), (float)-sweepAngle); + g.CloseFigure(); + } + } + + curpos = endpt; + } + + private void DrawRapids(Graphics g) + { + var pos = new Vector(0, 0); + + for (int i = 0; i < Plate.Parts.Count; ++i) + { + var part = Plate.Parts[i]; + var pgm = part.Program; + + DrawLine(g, pos, part.Location, rapidPen); + pos = part.Location; + DrawRapids(g, pgm, ref pos); + } + } + + private void DrawRapids(Graphics g, PepLib.Program pgm, ref Vector pos) + { + for (int i = 0; i < pgm.Count; ++i) + { + var code = pgm[i]; + + if (code.CodeType() == CodeType.SubProgramCall) + { + var subpgm = (SubProgramCall)code; + var loop = subpgm.Loop; + + if (loop != null) + DrawRapids(g, loop, ref pos); + } + else + { + var motion = code as Motion; + + if (motion != null) + { + + if (pgm.Mode == ProgrammingMode.Incremental) + { + var endpt = motion.EndPoint + pos; + + if (code.CodeType() == CodeType.RapidMove) + DrawLine(g, pos, endpt, rapidPen); + pos = endpt; + } + else + { + if (code.CodeType() == CodeType.RapidMove) + DrawLine(g, pos, motion.EndPoint, rapidPen); + pos = motion.EndPoint; + } + } + } + } + } + + private void DrawLine(Graphics g, Vector pt1, Vector pt2, Pen pen) + { + var point1 = PointWorldToGraph(pt1); + var point2 = PointWorldToGraph(pt2); + + g.DrawLine(pen, point1, point2); + } + + private void DrawBox(Graphics g, Box box) + { + var rect = new RectangleF() + { + Location = PointWorldToGraph(box.Location), + Width = LengthWorldToGui(box.Width), + Height = LengthWorldToGui(box.Height) + }; + + g.DrawRectangle(Pens.Orange, rect.X, rect.Y - rect.Height, rect.Width, rect.Height); + } + + private void UpdatePaths() + { + paths = new GraphicsPath[Plate.Parts.Count]; + + for (int i = 0; i < Plate.Parts.Count; ++i) + { + var part = Plate.Parts[i]; + var path = new GraphicsPath(); + + curpos = part.Location; + DrawProgram(path, part.Program); + + paths[i] = path; + } + + pathsNeedUpdated = false; + } + + public float LengthWorldToGui(double length) + { + return scale * (float)length; + } + + public double LengthGuiToWorld(float length) + { + return length / scale; + } + + /// + /// Returns a point with coordinates relative to the control from the graph. + /// + /// + /// + /// + public Point PointGraphToControl(float x, float y) + { + return new Point((int)(x + origin.X), (int)(y + origin.Y)); + } + + /// + /// Returns a point with coordinates relative to the control from the graph. + /// + /// + /// + public Point PointGraphToControl(PointF pt) + { + return PointGraphToControl(pt.X, pt.Y); + } + + /// + /// Returns a point with coordinates relative to the control from the world. + /// + /// + /// + /// + public Point PointWorldToControl(double x, double y) + { + return PointGraphToControl(PointWorldToGraph(x, y)); + } + + /// + /// Returns a point with coordinates relative to the control from the world. + /// + /// + /// + public Point PointWorldToControl(Vector pt) + { + return PointGraphToControl(PointWorldToGraph(pt.X, pt.Y)); + } + + /// + /// Returns a point with coordinates relative to the graph from the control. + /// + /// + /// + /// + public PointF PointControlToGraph(int x, int y) + { + return new PointF(x - origin.X, y - origin.Y); + } + + /// + /// Returns a point with coordinates relative to the graph from the control. + /// + /// + /// + public PointF PointControlToGraph(Point pt) + { + return PointControlToGraph(pt.X, pt.Y); + } + + /// + /// Returns a point with coordinates relative to the graph from the world. + /// + /// + /// + /// + public PointF PointWorldToGraph(double x, double y) + { + return new PointF(scale * (float)x, -scale * (float)y); + } + + /// + /// Returns a point with coordinates relative to the graph from the world. + /// + /// + /// + public PointF PointWorldToGraph(Vector pt) + { + return PointWorldToGraph(pt.X, pt.Y); + } + + /// + /// Returns a point with coordinates relative to the world from the control. + /// + /// + /// + /// + public Vector PointControlToWorld(int x, int y) + { + return PointGraphToWorld(PointControlToGraph(x, y)); + } + + /// + /// Returns a point with coordinates relative to the world from the control. + /// + /// + /// + /// + public Vector PointControlToWorld2(int x, int y) + { + return PointGraphToWorld2(PointControlToGraph(x, y)); + } + + /// + /// Returns a point with coordinates relative to the world from the control. + /// + /// + /// + public Vector PointControlToWorld(Point pt) + { + return PointGraphToWorld(PointControlToGraph(pt.X, pt.Y)); + } + + /// + /// Returns a point with coordinates relative to the world from the control. + /// + /// + /// + public Vector PointControlToWorld2(Point pt) + { + return PointGraphToWorld2(PointControlToGraph(pt.X, pt.Y)); + } + + /// + /// Returns a point with coordinates relative to the world from the graph. + /// + /// + /// + /// + public Vector PointGraphToWorld(float x, float y) + { + return new Vector( + MathHelper.RoundToNearest(x / scale, 0.03125), + MathHelper.RoundToNearest(y / -scale, 0.03125)); + } + + /// + /// Returns a point with coordinates relative to the world from the graph. + /// + /// + /// + /// + public Vector PointGraphToWorld2(float x, float y) + { + return new Vector(x / scale, y / -scale); + } + + /// + /// Returns a point with coordinates relative to the world from the graph. + /// + /// + /// + public Vector PointGraphToWorld(PointF pt) + { + return PointGraphToWorld(pt.X, pt.Y); + } + + /// + /// Returns a point with coordinates relative to the world from the graph. + /// + /// + /// + public Vector PointGraphToWorld2(PointF pt) + { + return PointGraphToWorld2(pt.X, pt.Y); + } + + public void RequestPathUpdate() + { + pathsNeedUpdated = true; + } + + public void ZoomToPoint(Point pt, float zoomFactor) + { + var pt2 = PointControlToWorld(pt); + + origin.X -= (float)(pt2.X * zoomFactor - pt2.X) * scale; + origin.Y += (float)(pt2.Y * zoomFactor - pt2.Y) * scale; + + scale *= zoomFactor; + + pathsNeedUpdated = true; + + Invalidate(); + } + + public void ZoomToFit() + { + ZoomToArea(Plate.GetBoundingBox(true)); + } + + public void ZoomToPlate() + { + float px; + float py; + + switch (Plate.Quadrant) + { + case 1: + px = 0; + py = 0; + break; + + case 2: + px = (float)-Plate.Size.Width; + py = 0; + break; + + case 3: + px = (float)-Plate.Size.Width; + py = (float)-Plate.Size.Height; + break; + + case 4: + px = 0; + py = (float)-Plate.Size.Height; + break; + + default: + return; + } + + ZoomToArea(px, py, (float)Plate.Size.Width, (float)Plate.Size.Height); + } + + public void ZoomToArea(Box box) + { + ZoomToArea(box.X, box.Y, box.Width, box.Height); + } + + public void ZoomToArea(double x, double y, double width, double height) + { + if (width <= 0 || height <= 0) + return; + + var a = (Height - BorderWidth) / height; + var b = (Width - BorderWidth) / width; + + scale = (float)(a < b ? a : b); + + var px = LengthWorldToGui(x); + var py = LengthWorldToGui(y); + var pw = LengthWorldToGui(width); + var ph = LengthWorldToGui(height); + + origin.X = (Width - pw) * 0.5f - px; + origin.Y = (Height + ph) * 0.5f + py; + + pathsNeedUpdated = true; + + Invalidate(); + } + + private static double NormalizeAngle(double angle) + { + double r = angle % 360.0; + return r < 0 ? 360.0 + r : r; + } + + public Part GetPartAtPoint(Point pt) + { + if (pathsNeedUpdated || paths.Length != Plate.Parts.Count) + UpdatePaths(); + + var pt2 = new PointF(pt.X - origin.X, pt.Y - origin.Y); + + for (int i = Plate.Parts.Count - 1; i >= 0; i--) + { + var path = paths[i]; + + if (path.IsVisible(pt2)) + return Plate.Parts[i]; + } + + return null; + } + } +} diff --git a/PepLib.UI/PepLib.UI.csproj b/PepLib.UI/PepLib.UI.csproj new file mode 100644 index 0000000..50d2e0c --- /dev/null +++ b/PepLib.UI/PepLib.UI.csproj @@ -0,0 +1,86 @@ + + + + + Debug + AnyCPU + {7A7D21F5-8EF1-4A63-A65B-86D10BEDFC2A} + Library + Properties + PepLib.UI + PepLib.UI + v4.0 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + Component + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + {22360453-b878-49fa-a5dc-0d9c577de902} + PepLib + + + + + \ No newline at end of file diff --git a/PepLib.UI/Properties/AssemblyInfo.cs b/PepLib.UI/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..79e1c39 --- /dev/null +++ b/PepLib.UI/Properties/AssemblyInfo.cs @@ -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("PepLib.UI")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PepLib.UI")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[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("7a7d21f5-8ef1-4a63-a65b-86d10bedfc2a")] + +// 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")] diff --git a/PepLib.UI/Properties/Resources.Designer.cs b/PepLib.UI/Properties/Resources.Designer.cs new file mode 100644 index 0000000..5de725f --- /dev/null +++ b/PepLib.UI/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PepLib.UI.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PepLib.UI.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/PepLib.UI/Properties/Resources.resx b/PepLib.UI/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/PepLib.UI/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/PepLib.UI/Properties/Settings.Designer.cs b/PepLib.UI/Properties/Settings.Designer.cs new file mode 100644 index 0000000..61c12e1 --- /dev/null +++ b/PepLib.UI/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PepLib.UI.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/PepLib.UI/Properties/Settings.settings b/PepLib.UI/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/PepLib.UI/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/PepLib.sln b/PepLib.sln new file mode 100644 index 0000000..b88be71 --- /dev/null +++ b/PepLib.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepLib", "PepLib\PepLib.csproj", "{22360453-B878-49FA-A5DC-0D9C577DE902}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepLib.Dxf", "PepLib.Dxf\PepLib.Dxf.csproj", "{E15A7403-B16D-4D11-A061-2F5E98DF36B0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepLib.UI", "PepLib.UI\PepLib.UI.csproj", "{7A7D21F5-8EF1-4A63-A65B-86D10BEDFC2A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {22360453-B878-49FA-A5DC-0D9C577DE902}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22360453-B878-49FA-A5DC-0D9C577DE902}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22360453-B878-49FA-A5DC-0D9C577DE902}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22360453-B878-49FA-A5DC-0D9C577DE902}.Release|Any CPU.Build.0 = Release|Any CPU + {E15A7403-B16D-4D11-A061-2F5E98DF36B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E15A7403-B16D-4D11-A061-2F5E98DF36B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E15A7403-B16D-4D11-A061-2F5E98DF36B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E15A7403-B16D-4D11-A061-2F5E98DF36B0}.Release|Any CPU.Build.0 = Release|Any CPU + {7A7D21F5-8EF1-4A63-A65B-86D10BEDFC2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A7D21F5-8EF1-4A63-A65B-86D10BEDFC2A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A7D21F5-8EF1-4A63-A65B-86D10BEDFC2A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A7D21F5-8EF1-4A63-A65B-86D10BEDFC2A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/PepLib/AngleConverter.cs b/PepLib/AngleConverter.cs new file mode 100644 index 0000000..50c30dd --- /dev/null +++ b/PepLib/AngleConverter.cs @@ -0,0 +1,17 @@ +using System; + +namespace PepLib +{ + public static class AngleConverter + { + public static double ToDegrees(double radians) + { + return 180.0 / Math.PI * radians; + } + + public static double ToRadians(double degrees) + { + return Math.PI / 180.0 * degrees; + } + } +} diff --git a/PepLib/ApplicationType.cs b/PepLib/ApplicationType.cs new file mode 100644 index 0000000..98bb2ac --- /dev/null +++ b/PepLib/ApplicationType.cs @@ -0,0 +1,15 @@ + +namespace PepLib +{ + public enum ApplicationType + { + None = 0x0, + Laser = 0x1, + Flame = 0x2, + Punch = 0x3, + PlasmaPunch = 0x4, + Waterjet = 0x6, + LaserPunch = 0x7, + FlamePlasma = 0x9 + } +} diff --git a/PepLib/Box.cs b/PepLib/Box.cs new file mode 100644 index 0000000..e42fc73 --- /dev/null +++ b/PepLib/Box.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PepLib +{ + public class Box + { + public Box() + : this(0, 0, 0, 0) + { + } + + public Box(double x, double y, double w, double h) + { + Location = new Vector(x, y); + Size = new PepLib.Size(0, 0); + Width = w; + Height = h; + } + + public Vector Location; + + public Vector Center + { + get { return new Vector(X + Width * 0.5, Y + Height * 0.5); } + } + + public Size Size; + + public double X + { + get { return Location.X; } + set { Location.X = value; } + } + + public double Y + { + get { return Location.Y; } + set { Location.Y = value; } + } + + public double Width + { + get { return Size.Width; } + set { Size.Width = value; } + } + + public double Height + { + get { return Size.Height; } + set { Size.Height = value; } + } + + public void MoveTo(double x, double y) + { + X = x; + Y = y; + } + + public void MoveTo(Vector pt) + { + X = pt.X; + Y = pt.Y; + } + + public void Offset(double x, double y) + { + X += x; + Y += y; + } + + public void Offset(Vector voffset) + { + Location += voffset; + } + + public double Left + { + get { return X; } + } + + public double Right + { + get { return X + Width; } + } + + public double Top + { + get { return Y + Height; } + } + + public double Bottom + { + get { return Y; } + } + + public double Area() + { + return Width * Height; + } + + public double Perimeter() + { + return Width * 2 + Height * 2; + } + + public bool IsIntersecting(Box box) + { + if (Left >= box.Right) + return false; + + if (Right >= box.Left) + return false; + + if (Top <= box.Bottom) + return false; + + if (Bottom <= box.Top) + return false; + + return true; + } + + public bool Contains(Box box) + { + if (box.Left < Left) + return false; + + if (box.Right > Right) + return false; + + if (box.Bottom < Bottom) + return false; + + if (box.Top > Top) + return false; + + return true; + } + + public bool Contains(Vector pt) + { + return pt.X >= Left && pt.X <= Right + && pt.Y >= Bottom && pt.Y <= Top; + } + + public override string ToString() + { + return string.Format("[Box: X={0}, Y={1}, Width={2}, Height={3}]", X, Y, Width, Height); + } + } +} diff --git a/PepLib/Codes/CircularMove.cs b/PepLib/Codes/CircularMove.cs new file mode 100644 index 0000000..7032fa5 --- /dev/null +++ b/PepLib/Codes/CircularMove.cs @@ -0,0 +1,74 @@ + +namespace PepLib.Codes +{ + public class CircularMove : Motion + { + public CircularMove() + { + } + + public CircularMove(Vector endPoint, Vector centerPoint, RotationType rotation = RotationType.CCW) + { + EndPoint = endPoint; + CenterPoint = centerPoint; + Rotation = rotation; + } + + public CircularMove(double x, double y, double i, double j, RotationType rotation = RotationType.CCW) + { + EndPoint = new Vector(x, y); + CenterPoint = new Vector(i, j); + Rotation = rotation; + } + + public RotationType Rotation { get; set; } + + public EntityType Type { get; set; } + + public Vector CenterPoint { get; set; } + + public override void Rotate(double angle) + { + base.Rotate(angle); + CenterPoint = CenterPoint.Rotate(angle); + } + + public override void Rotate(double angle, Vector origin) + { + base.Rotate(angle, origin); + CenterPoint = CenterPoint.Rotate(angle, origin); + } + + public override void Offset(double x, double y) + { + base.Offset(x, y); + CenterPoint = new Vector(CenterPoint.X + x, CenterPoint.Y + y); + } + + public override void Offset(Vector voffset) + { + base.Offset(voffset); + CenterPoint += voffset; + } + + public override CodeType CodeType() + { + return Codes.CodeType.CircularMove; + } + + public override ICode Clone() + { + return new CircularMove(EndPoint, CenterPoint, Rotation) + { + Type = Type + }; + } + + public override string ToString() + { + return Rotation == RotationType.CW ? + string.Format("G02 X{0} Y{1} I{2} J{3}", EndPoint.X, EndPoint.Y, CenterPoint.X, CenterPoint.Y) : + string.Format("G03 X{0} Y{1} I{2} J{3}", EndPoint.X, EndPoint.Y, CenterPoint.X, CenterPoint.Y); + } + } +} diff --git a/PepLib/Codes/CodeType.cs b/PepLib/Codes/CodeType.cs new file mode 100644 index 0000000..a1c3136 --- /dev/null +++ b/PepLib/Codes/CodeType.cs @@ -0,0 +1,14 @@ + +namespace PepLib.Codes +{ + public enum CodeType + { + CircularMove, + Comment, + LinearMove, + RapidMove, + SetFeedrate, + SetKerf, + SubProgramCall + } +} diff --git a/PepLib/Codes/Comment.cs b/PepLib/Codes/Comment.cs new file mode 100644 index 0000000..434a23b --- /dev/null +++ b/PepLib/Codes/Comment.cs @@ -0,0 +1,32 @@ + +namespace PepLib.Codes +{ + public class Comment : ICode + { + public Comment() + { + } + + public Comment(string value) + { + Value = value; + } + + public string Value { get; set; } + + public CodeType CodeType() + { + return Codes.CodeType.Comment; + } + + public ICode Clone() + { + return new Comment(Value); + } + + public override string ToString() + { + return ':' + Value; + } + } +} diff --git a/PepLib/Codes/EntityType.cs b/PepLib/Codes/EntityType.cs new file mode 100644 index 0000000..8c93f03 --- /dev/null +++ b/PepLib/Codes/EntityType.cs @@ -0,0 +1,13 @@ +namespace PepLib.Codes +{ + public enum EntityType + { + Display, + Scribe, + Cut, + InternalLeadin, + InternalLeadout, + ExternalLeadin, + ExternalLeadout + } +} diff --git a/PepLib/Codes/ICode.cs b/PepLib/Codes/ICode.cs new file mode 100644 index 0000000..ed78d86 --- /dev/null +++ b/PepLib/Codes/ICode.cs @@ -0,0 +1,8 @@ +namespace PepLib.Codes +{ + public interface ICode + { + CodeType CodeType(); + ICode Clone(); + } +} diff --git a/PepLib/Codes/LinearMove.cs b/PepLib/Codes/LinearMove.cs new file mode 100644 index 0000000..f4c92a8 --- /dev/null +++ b/PepLib/Codes/LinearMove.cs @@ -0,0 +1,42 @@ + +namespace PepLib.Codes +{ + public class LinearMove : Motion + { + public LinearMove() + : this(new Vector()) + { + } + + public LinearMove(double x, double y) + : this(new Vector(x, y)) + { + } + + public LinearMove(Vector endPoint) + { + EndPoint = endPoint; + Type = EntityType.Cut; + } + + public EntityType Type { get; set; } + + public override CodeType CodeType() + { + return Codes.CodeType.LinearMove; + } + + public override ICode Clone() + { + return new LinearMove(EndPoint) + { + Type = Type + }; + } + + public override string ToString() + { + return string.Format("G01 X{0} Y{1}", EndPoint.X, EndPoint.Y); + } + } +} diff --git a/PepLib/Codes/Motion.cs b/PepLib/Codes/Motion.cs new file mode 100644 index 0000000..220418d --- /dev/null +++ b/PepLib/Codes/Motion.cs @@ -0,0 +1,32 @@ + +namespace PepLib.Codes +{ + public abstract class Motion : IMovable, ICode + { + public Vector EndPoint { get; set; } + + public virtual void Rotate(double angle) + { + EndPoint = EndPoint.Rotate(angle); + } + + public virtual void Rotate(double angle, Vector origin) + { + EndPoint = EndPoint.Rotate(angle, origin); + } + + public virtual void Offset(double x, double y) + { + EndPoint = new Vector(EndPoint.X + x, EndPoint.Y + y); + } + + public virtual void Offset(Vector voffset) + { + EndPoint += voffset; + } + + public abstract CodeType CodeType(); + + public abstract ICode Clone(); + } +} diff --git a/PepLib/Codes/RapidMove.cs b/PepLib/Codes/RapidMove.cs new file mode 100644 index 0000000..746e99c --- /dev/null +++ b/PepLib/Codes/RapidMove.cs @@ -0,0 +1,34 @@ +namespace PepLib.Codes +{ + public class RapidMove : Motion + { + public RapidMove() + { + } + + public RapidMove(Vector endPoint) + { + EndPoint = endPoint; + } + + public RapidMove(double x, double y) + { + EndPoint = new Vector(x, y); + } + + public override CodeType CodeType() + { + return Codes.CodeType.RapidMove; + } + + public override ICode Clone() + { + return new RapidMove(EndPoint); + } + + public override string ToString() + { + return string.Format("G00 X{0} Y{1}", EndPoint.X, EndPoint.Y); + } + } +} diff --git a/PepLib/Codes/SetFeedrate.cs b/PepLib/Codes/SetFeedrate.cs new file mode 100644 index 0000000..6095f35 --- /dev/null +++ b/PepLib/Codes/SetFeedrate.cs @@ -0,0 +1,32 @@ + +namespace PepLib.Codes +{ + public class SetFeedrate : ICode + { + public SetFeedrate() + { + } + + public SetFeedrate(double value) + { + Value = value; + } + + public double Value { get; set; } + + public CodeType CodeType() + { + return Codes.CodeType.SetFeedrate; + } + + public ICode Clone() + { + return new SetFeedrate(Value); + } + + public override string ToString() + { + return string.Format("F{0}", Value); + } + } +} diff --git a/PepLib/Codes/SetKerf.cs b/PepLib/Codes/SetKerf.cs new file mode 100644 index 0000000..97d2c99 --- /dev/null +++ b/PepLib/Codes/SetKerf.cs @@ -0,0 +1,34 @@ + +namespace PepLib.Codes +{ + public class SetKerf : ICode + { + public SetKerf(KerfType kerf = KerfType.Left) + { + Kerf = kerf; + } + + public KerfType Kerf { get; set; } + + public CodeType CodeType() + { + return Codes.CodeType.SetKerf; + } + + public ICode Clone() + { + return new SetKerf(Kerf); + } + + public override string ToString() + { + if (Kerf == KerfType.None) + return "G40"; + + if (Kerf == KerfType.Left) + return "G41"; + + return "G42"; + } + } +} diff --git a/PepLib/Codes/SubProgramCall.cs b/PepLib/Codes/SubProgramCall.cs new file mode 100644 index 0000000..47eaebd --- /dev/null +++ b/PepLib/Codes/SubProgramCall.cs @@ -0,0 +1,85 @@ + +namespace PepLib.Codes +{ + public class SubProgramCall : ICode + { + private double rotation; + private Loop loop; + + public SubProgramCall() + { + } + + public SubProgramCall(int loopId, int repeatCount, double rotation) + { + LoopId = loopId; + RepeatCount = repeatCount; + Rotation = rotation; + } + + /// + /// The id associated with the current set loop. + /// + public int LoopId { get; set; } + + /// + /// Number of times the loop is cut. + /// + public int RepeatCount { get; set; } + + /// + /// Gets or sets the loop associated with the loop id. + /// + public Loop Loop + { + get { return loop; } + set + { + loop = (Loop)value.Clone(); + UpdateLoopRotation(); + } + } + + /// + /// Gets or sets the current rotation of the loop in degrees. + /// + public double Rotation + { + get { return rotation; } + set + { + rotation = value; + UpdateLoopRotation(); + } + } + + private void UpdateLoopRotation() + { + if (loop != null) + { + var diffAngle = AngleConverter.ToRadians(rotation) - loop.Rotation; + + if (!diffAngle.IsEqualTo(0.0)) + loop.Rotate(diffAngle); + } + } + + public CodeType CodeType() + { + return Codes.CodeType.SubProgramCall; + } + + public ICode Clone() + { + return new SubProgramCall(LoopId, RepeatCount, Rotation) + { + Loop = Loop + }; + } + + public override string ToString() + { + return string.Format("G92 L{0} R{1} P{2}", LoopId, RepeatCount, Rotation); + } + } +} diff --git a/PepLib/Drawing.cs b/PepLib/Drawing.cs new file mode 100644 index 0000000..7dc816b --- /dev/null +++ b/PepLib/Drawing.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections.Generic; +using System.IO; +using PepLib.IO; + +namespace PepLib +{ + public class Drawing + { + public DrawingInfo Info { get; set; } + + public List Loops { get; set; } + + public Drawing() + { + Loops = new List(); + } + + public static Drawing Load(string nestfile) + { + var reader = new DrawingReader(); + reader.Read(nestfile); + return reader.Drawing; + } + + public static Drawing Load(Stream stream) + { + var reader = new DrawingReader(); + reader.Read(stream); + return reader.Drawing; + } + + public static bool TryLoad(string nestfile, out Drawing drawing) + { + try + { + drawing = Load(nestfile); + } + catch (Exception) + { + drawing = null; + return false; + } + + return true; + } + + public static bool TryLoad(Stream stream, out Drawing drawing) + { + try + { + drawing = Load(stream); + } + catch (Exception) + { + drawing = null; + return false; + } + + return true; + } + + #region DrawingInfo wrapper properties + + public string Name + { + get { return Info.Name; } + set { Info.Name = value; } + } + + public string Revision + { + get { return Info.Revision; } + set { Info.Revision = value; } + } + + public string Customer + { + get { return Info.Customer; } + set { Info.Customer = value; } + } + + public string Description + { + get { return Info.Description; } + set { Info.Description = value; } + } + + public string Comment + { + get { return Info.Comment; } + set { Info.Comment = value; } + } + + public string Notes + { + get { return Info.Notes; } + set { Info.Notes = value; } + } + + public string Source + { + get { return Info.Source; } + set { Info.Source = value; } + } + + public DateTime CreationDate + { + get { return Info.CreationDate; } + set { Info.CreationDate = value; } + } + + public DateTime LastModifiedDate + { + get { return Info.LastModifiedDate; } + set { Info.LastModifiedDate = value; } + } + + public DateTime LastReferenceDate + { + get { return Info.LastReferenceDate; } + set { Info.LastReferenceDate = value; } + } + + public int MachineNumber + { + get { return Info.MachineNumber; } + set { Info.MachineNumber = value; } + } + + public ApplicationType Application + { + get { return Info.Application; } + set { Info.Application = value; } + } + + public int MaterialNumber + { + get { return Info.MaterialNumber; } + set { Info.MaterialNumber = value; } + } + + public string MaterialGrade + { + get { return Info.MaterialGrade; } + set { Info.MaterialGrade = value; } + } + + public string Specification + { + get { return Info.Specification; } + set { Info.Specification = value; } + } + + public string Hardness + { + get { return Info.Hardness; } + set { Info.Hardness = value; } + } + + public GrainType Grain + { + get { return Info.Grain; } + set { Info.Grain = value; } + } + + public string ProgrammedBy + { + get { return Info.ProgrammedBy; } + set { Info.ProgrammedBy = value; } + } + + public string CreatedBy + { + get { return Info.CreatedBy; } + set { Info.CreatedBy = value; } + } + + public string Errors + { + get { return Info.Errors; } + set { Info.Errors = value; } + } + + public DrawingType Type + { + get { return Info.Type; } + set { Info.Type = value; } + } + + public string UserDefined1 + { + get { return Info.UserDefined1; } + set { Info.UserDefined1 = value; } + } + + public string UserDefined2 + { + get { return Info.UserDefined2; } + set { Info.UserDefined2 = value; } + } + + public string UserDefined3 + { + get { return Info.UserDefined3; } + set { Info.UserDefined3 = value; } + } + + public string UserDefined4 + { + get { return Info.UserDefined4; } + set { Info.UserDefined4 = value; } + } + + public string UserDefined5 + { + get { return Info.UserDefined5; } + set { Info.UserDefined5 = value; } + } + + public string UserDefined6 + { + get { return Info.UserDefined6; } + set { Info.UserDefined6 = value; } + } + + #endregion + } +} diff --git a/PepLib/DrawingInfo.cs b/PepLib/DrawingInfo.cs new file mode 100644 index 0000000..d5d84be --- /dev/null +++ b/PepLib/DrawingInfo.cs @@ -0,0 +1,109 @@ +using System; +using System.IO; +using System.Text; +using PepLib.IO; + +namespace PepLib +{ + public class DrawingInfo + { + public string Name { get; set; } + + public string Revision { get; set; } + + public string Customer { get; set; } + + public string Description { get; set; } + + public string Comment { get; set; } + + public string Notes { get; set; } + + public string Source { get; set; } + + public DateTime CreationDate { get; set; } + + public DateTime LastModifiedDate { get; set; } + + public DateTime LastReferenceDate { get; set; } + + public int MachineNumber { get; set; } + + public ApplicationType Application { get; set; } + + public int MaterialNumber { get; set; } + + public string MaterialGrade { get; set; } + + public string Specification { get; set; } + + public string Hardness { get; set; } + + public GrainType Grain { get; set; } + + public string ProgrammedBy { get; set; } + + public string CreatedBy { get; set; } + + public string Errors { get; set; } + + public DrawingType Type { get; set; } + + public string UserDefined1 { get; set; } + + public string UserDefined2 { get; set; } + + public string UserDefined3 { get; set; } + + public string UserDefined4 { get; set; } + + public string UserDefined5 { get; set; } + + public string UserDefined6 { get; set; } + + public static DrawingInfo Load(string nestFile) + { + var reader = new DrawingInfoReader(); + reader.Read(nestFile); + return reader.Info; + } + + public static DrawingInfo Load(Stream stream) + { + var reader = new DrawingInfoReader(); + reader.Read(stream); + return reader.Info; + } + + public static bool TryLoad(string nestfile, out DrawingInfo drawingInfo) + { + try + { + drawingInfo = Load(nestfile); + } + catch (Exception) + { + drawingInfo = null; + return false; + } + + return true; + } + + public static bool TryLoad(Stream stream, out DrawingInfo drawingInfo) + { + try + { + drawingInfo = Load(stream); + } + catch (Exception) + { + drawingInfo = null; + return false; + } + + return true; + } + } +} + diff --git a/PepLib/DrawingType.cs b/PepLib/DrawingType.cs new file mode 100644 index 0000000..dd5c0d0 --- /dev/null +++ b/PepLib/DrawingType.cs @@ -0,0 +1,12 @@ + +namespace PepLib +{ + public enum DrawingType + { + None = 0x20, + Drawing = 0x44, + Product = 0x50, + Rotary = 0x52, + Tool = 0x54 + } +} diff --git a/PepLib/Generic.cs b/PepLib/Generic.cs new file mode 100644 index 0000000..aaf4cea --- /dev/null +++ b/PepLib/Generic.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PepLib +{ + public static class Generic + { + public static void Swap(ref T a, ref T b) + { + T c = a; + a = b; + b = c; + } + } +} diff --git a/PepLib/GrainType.cs b/PepLib/GrainType.cs new file mode 100644 index 0000000..6a4345c --- /dev/null +++ b/PepLib/GrainType.cs @@ -0,0 +1,11 @@ + +namespace PepLib +{ + public enum GrainType + { + No = 0x0, + Yes = 0x1, + Soft = 0x2, + Hard = 0x3 + } +} diff --git a/PepLib/IMovable.cs b/PepLib/IMovable.cs new file mode 100644 index 0000000..c76b3ac --- /dev/null +++ b/PepLib/IMovable.cs @@ -0,0 +1,10 @@ +namespace PepLib +{ + public interface IMovable + { + void Rotate(double angle); + void Rotate(double angle, Vector origin); + void Offset(double x, double y); + void Offset(Vector voffset); + } +} diff --git a/PepLib/IO/DrawingInfoReader.cs b/PepLib/IO/DrawingInfoReader.cs new file mode 100644 index 0000000..a141e03 --- /dev/null +++ b/PepLib/IO/DrawingInfoReader.cs @@ -0,0 +1,100 @@ +using System; +using System.IO; +using System.Text; + +namespace PepLib.IO +{ + public sealed class DrawingInfoReader + { + public DrawingInfo Info { get; private set; } + + public DrawingInfoReader() + { + Info = new DrawingInfo(); + } + + public DrawingInfoReader(DrawingInfo info) + { + Info = info; + } + + public void Read(Stream stream) + { + Info.Name = ReadString(0xC8, ref stream); + Info.Revision = ReadString(0x20, ref stream); + Info.CreationDate = DateTime.Parse(ReadString(0xA, ref stream)); + Info.LastModifiedDate = DateTime.Parse(ReadString(0xA, ref stream)); + Info.LastReferenceDate = DateTime.Parse(ReadString(0xA, ref stream)); + Info.Description = ReadString(0xC8, ref stream); + Info.Customer = ReadString(0x40, ref stream); + Info.Comment = ReadString(0x40, ref stream); + Info.Notes = ReadString(0x400, ref stream); + Info.Grain = (GrainType)ReadByte(ref stream); + + stream.Seek(0x9, SeekOrigin.Current); + + Info.MaterialNumber = int.Parse(ReadString(0x40, ref stream)); + Info.MaterialGrade = ReadString(0x10, ref stream); + Info.ProgrammedBy = ReadString(0x40, ref stream); + Info.CreatedBy = ReadString(0x40, ref stream); + Info.Type = (DrawingType)ReadByte(ref stream); + + stream.Seek(0x4, SeekOrigin.Current); + + Info.Errors = ReadString(0x64, ref stream); + Info.Hardness = ReadString(0x20, ref stream); + Info.Specification = ReadString(0x40, ref stream); + + stream.Seek(0x2, SeekOrigin.Current); + + Info.UserDefined1 = ReadString(0x20, ref stream); + Info.UserDefined2 = ReadString(0x20, ref stream); + Info.UserDefined3 = ReadString(0x20, ref stream); + Info.UserDefined4 = ReadString(0x40, ref stream); + Info.UserDefined5 = ReadString(0x40, ref stream); + Info.UserDefined6 = ReadString(0x40, ref stream); + Info.MachineNumber = ReadByte(ref stream); + + stream.Seek(0x1, SeekOrigin.Current); + + Info.Application = (ApplicationType)ReadByte(ref stream); + } + + public void Read(string nestFile) + { + if (!File.Exists(nestFile)) + { + var msg = string.Format("File Not Found: {0}", nestFile); + throw new FileNotFoundException(msg); + } + + Stream stream = null; + string name; + + try + { + ZipHelper.ExtractByExtension(nestFile, ".dir", out name, out stream); + Read(stream); + } + finally + { + if (stream != null) + stream.Close(); + } + } + + private static string ReadString(int length, ref Stream stream) + { + var buffer = new byte[length]; + stream.Read(buffer, 0, length); + return Encoding.Default.GetString(buffer).Trim(); + } + + private static byte ReadByte(ref Stream stream) + { + var buffer = new byte[0x1]; + stream.Read(buffer, 0, 1); + return buffer[0]; + } + } +} diff --git a/PepLib/IO/DrawingReader.cs b/PepLib/IO/DrawingReader.cs new file mode 100644 index 0000000..b9396c0 --- /dev/null +++ b/PepLib/IO/DrawingReader.cs @@ -0,0 +1,112 @@ +using Ionic.Zip; +using System; +using System.Diagnostics; +using System.IO; +using System.Text.RegularExpressions; + +namespace PepLib.IO +{ + public sealed class DrawingReader + { + public Drawing Drawing { get; private set; } + + public DrawingReader() + { + Drawing = new Drawing(); + } + + public DrawingReader(Drawing drawing) + { + Drawing = drawing; + } + + public void Read(Stream stream) + { + var drawing = new Drawing(); + var zipStream = new ZipInputStream(stream); + + ZipEntry theEntry; + + while ((theEntry = zipStream.GetNextEntry()) != null) + { + var size = 2048; + var data = new byte[size]; + var memstream = new MemoryStream(); + + while (true) + { + size = zipStream.Read(data, 0, data.Length); + + if (size > 0) + { + memstream.Write(data, 0, size); + memstream.Flush(); + } + else break; + } + + memstream.Seek(0, SeekOrigin.Begin); + + var extension = Path.GetExtension(theEntry.FileName); + + switch (extension) + { + case ".dir": + LoadInfo(memstream); + memstream.Close(); + continue; + } + + if (Regex.IsMatch(extension, "loop-\\d\\d\\d")) + drawing.Loops.Add(ReadLoop(theEntry.FileName, memstream)); + + memstream.Close(); + } + + zipStream.Close(); + } + + public void Read(string nestFile) + { + if (!File.Exists(nestFile)) + { + var msg = string.Format("File Not Found: {0}", nestFile); + throw new FileNotFoundException(msg); + } + + Stream stream = null; + + try + { + stream = new FileStream(nestFile, FileMode.Open); + Read(stream); + } + finally + { + if (stream != null) + stream.Close(); + } + } + + private void LoadInfo(Stream stream) + { + try + { + Drawing.Info = DrawingInfo.Load(stream); + } + catch (Exception exception) + { + Debug.WriteLine(exception.Message); + Debug.WriteLine(exception.StackTrace); + } + } + + private Loop ReadLoop(string name, Stream stream) + { + var reader = new LoopReader(); + reader.Read(name, stream); + + return reader.Loop; + } + } +} diff --git a/PepLib/IO/LoopReader.cs b/PepLib/IO/LoopReader.cs new file mode 100644 index 0000000..7b98eb3 --- /dev/null +++ b/PepLib/IO/LoopReader.cs @@ -0,0 +1,134 @@ +using System; +using System.IO; +using PepLib.Codes; + +namespace PepLib.IO +{ + internal sealed class LoopReader + { + public Loop Loop { get; private set; } + + public LoopReader() + { + Loop = new Loop(); + } + + public LoopReader(Loop loop) + { + Loop = loop; + } + + public void Read(string name, Stream stream) + { + var pgm = Program.Load(stream); + + Loop.Name = name; + Loop.AddRange(pgm); + LoadInfo(); + } + + private void LoadInfo() + { + for (int i = Loop.Count - 1; i >= 0; --i) + { + var code = Loop[i]; + + if (code.CodeType() != CodeType.Comment) + continue; + + var comment = (Comment)code; + + if (LoadInfo(comment.Value)) + Loop.RemoveAt(i); + } + } + + private bool LoadInfo(string value) + { + if (value.StartsWith("REF")) + { + ParseReferenceData(value); + return true; + } + + if (value.StartsWith("DRAWING")) + { + ParseDrawingData(value); + return true; + } + + if (value.StartsWith("DXF")) + { + ParseDxfData(value); + return true; + } + + return false; + } + + private void ParseReferenceData(string data) + { + var parts = data.Split(','); + + if (parts.Length != 3) + return; + + int xindex = parts[0].IndexOf('X'); + parts[0] = parts[0].Remove(0, xindex); + + double x = 0; + double y = 0; + + var xsplit = parts[0].Split('='); + + if (xsplit.Length == 2) + x = ReadDouble(xsplit[1]); + + var ysplit = parts[1].Split('='); + + if (ysplit.Length == 2) + y = ReadDouble(ysplit[1]); + + var datesplit = parts[2].Split('='); + + if (datesplit.Length == 2) + { + DateTime date; + DateTime.TryParse(datesplit[1], out date); + Loop.LastReferenceDate = date; + } + + Loop.ReferencePoint = new Vector(x, y); + } + + private void ParseDrawingData(string data) + { + var index = data.IndexOf('='); + + if (index == -1) + Loop.DrawingName = string.Empty; + + Loop.DrawingName = data.Remove(0, index + 1).Trim(); + } + + private void ParseDxfData(string data) + { + var index = data.IndexOf('='); + + if (index == -1) + Loop.DxfPath = string.Empty; + + Loop.DxfPath = data.Remove(0, index + 1).Trim(); + } + + private static double ReadDouble(string s, double defaultValue = 0.0) + { + double f; + + if (!double.TryParse(s, out f)) + return defaultValue; + + return f; + } + } +} \ No newline at end of file diff --git a/PepLib/IO/MaterialDataReader.cs b/PepLib/IO/MaterialDataReader.cs new file mode 100644 index 0000000..1feebd2 --- /dev/null +++ b/PepLib/IO/MaterialDataReader.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace PepLib.IO +{ + public class MaterialDataReader + { + public List Materials { get; set; } + + public MaterialDataReader() + { + Materials = new List(); + } + + public void Read(Stream stream) + { + const int dataLength = 2000; + var count = stream.Length / dataLength; + + for (int i = 0; i < count; i++) + { + var data = new MaterialData(); + + int id; + int.TryParse(ReadString(64, ref stream), out id); + data.Id = id; + data.Grade = ReadString(16, ref stream); + data.Name = ReadString(200, ref stream); + + Materials.Add(data); + + stream.Position = i * dataLength; + } + } + + public void Read(string file) + { + if (!File.Exists(file)) + { + var msg = string.Format("File Not Found: {0}", file); + throw new FileNotFoundException(msg); + } + + Stream stream = null; + + try + { + stream = File.OpenRead(file); + Read(stream); + } + finally + { + if (stream != null) + stream.Close(); + } + } + + private static string ReadString(int length, ref Stream stream) + { + var buffer = new byte[length]; + stream.Read(buffer, 0, length); + return Encoding.Default.GetString(buffer).Trim(); + } + + private static byte ReadByte(ref Stream stream) + { + var buffer = new byte[0x1]; + stream.Read(buffer, 0, 1); + return buffer[0]; + } + } + + public class MaterialData + { + public int Id { get; set; } + + public string Name { get; set; } + + public string Grade { get; set; } + } +} diff --git a/PepLib/IO/NestInfoReader.cs b/PepLib/IO/NestInfoReader.cs new file mode 100644 index 0000000..73bec80 --- /dev/null +++ b/PepLib/IO/NestInfoReader.cs @@ -0,0 +1,124 @@ +using System; +using System.IO; +using System.Text; + +namespace PepLib.IO +{ + internal sealed class NestInfoReader + { + public NestInfo Info { get; private set; } + + public NestInfoReader() + { + Info = new NestInfo(); + } + + public NestInfoReader(NestInfo info) + { + Info = info; + } + + public void Read(Stream stream) + { + var binReader = new BinaryReader(stream); + + Info.Name = ReadString(0xC8, ref stream); + Info.DateCreated = DateTime.Parse(ReadString(0xA, ref stream)); + Info.DateLastModified = DateTime.Parse(ReadString(0xA, ref stream)); + Info.LoopCount = binReader.ReadInt16(); + Info.ProgramCount = binReader.ReadInt16(); + Info.Customer = ReadString(0x40, ref stream); + Info.ProgrammedBy = ReadString(0x40, ref stream); + Info.Comments = ReadString(0x40, ref stream); + + // skip 2 bytes + stream.Seek(0x2, SeekOrigin.Current); + + Info.MaterialNumber = int.Parse(ReadString(0x40, ref stream)); + Info.MaterialGrade = ReadString(0x10, ref stream); + + // skip 2 bytes + stream.Seek(0x2, SeekOrigin.Current); + + Info.Notes = ReadString(0x400, ref stream); + Info.PostedAs = ReadString(0x64, ref stream); + Info.Errors = ReadString(0x64, ref stream); + Info.UserDefined1 = ReadString(0x20, ref stream); + Info.UserDefined2 = ReadString(0x20, ref stream); + Info.UserDefined3 = ReadString(0x20, ref stream); + Info.UserDefined4 = ReadString(0x40, ref stream); + Info.UserDefined5 = ReadString(0x40, ref stream); + Info.UserDefined6 = ReadString(0x40, ref stream); + Info.DefaultPlateSize = ReadString(0x1E, ref stream); + Info.Kerf = ReadString(0x3, ref stream); + + // skip 4 bytes + stream.Seek(0x4, SeekOrigin.Current); + + switch (ReadByte(ref stream)) + { + case 0: + Info.Status = StatusType.ToBeCut; + break; + + case 1: + Info.Status = StatusType.Quote; + break; + + case 2: + Info.Status = StatusType.HasBeenCut; + break; + + case 3: + Info.Status = StatusType.Temp; + break; + + default: + Info.Status = StatusType.ToBeCut; + break; + } + + // skip 16 bytes + stream.Seek(16, SeekOrigin.Current); + + Info.PlateCount = binReader.ReadInt16(); + } + + public void Read(string nestFile) + { + if (!File.Exists(nestFile)) + { + var msg = string.Format("File Not Found: {0}", nestFile); + throw new FileNotFoundException(msg); + } + + Stream stream = null; + string name; + + try + { + ZipHelper.ExtractByExtension(nestFile, ".dir", out name, out stream); + Read(stream); + } + finally + { + if (stream != null) + stream.Close(); + } + } + + private static string ReadString(int length, ref Stream stream) + { + var buffer = new byte[length]; + stream.Read(buffer, 0, length); + return Encoding.Default.GetString(buffer).Trim(); + } + + private static byte ReadByte(ref Stream stream) + { + var buffer = new byte[0x1]; + stream.Read(buffer, 0, 1); + return buffer[0]; + } + } +} diff --git a/PepLib/IO/NestReader.cs b/PepLib/IO/NestReader.cs new file mode 100644 index 0000000..16f483a --- /dev/null +++ b/PepLib/IO/NestReader.cs @@ -0,0 +1,181 @@ +using Ionic.Zip; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; + +namespace PepLib.IO +{ + public sealed class NestReader + { + public Nest Nest { get; private set; } + + private readonly Dictionary plates; + private readonly Dictionary loops; + + public NestReader() + : this(new Nest()) + { + } + + public NestReader(Nest nest) + { + Nest = nest; + plates = new Dictionary(); + loops = new Dictionary(); + } + + public void Read(Stream stream) + { + const string plateExtensionPattern = "plate-\\d\\d\\d"; + const string loopExtensionPattern = "loop-\\d\\d\\d"; + + var zipStream = new ZipInputStream(stream); + + ZipEntry theEntry; + + while ((theEntry = zipStream.GetNextEntry()) != null) + { + var size = 2048; + var data = new byte[size]; + var memstream = new MemoryStream(); + + while (true) + { + size = zipStream.Read(data, 0, data.Length); + + if (size > 0) + { + memstream.Write(data, 0, size); + memstream.Flush(); + } + else break; + } + + memstream.Seek(0, SeekOrigin.Begin); + + var extension = Path.GetExtension(theEntry.FileName); + + switch (extension) + { + case ".dir": + LoadInfo(memstream); + memstream.Close(); + continue; + + case ".report": + LoadReport(memstream); + memstream.Close(); + continue; + + case ".dwg-info": + LoadDrawingInfo(memstream); + memstream.Close(); + continue; + + default: + Debug.WriteLine("Unknown file: " + theEntry.FileName); + break; + } + + if (Regex.IsMatch(extension, loopExtensionPattern)) + loops.Add(theEntry.FileName, memstream); + else if (Regex.IsMatch(extension, plateExtensionPattern)) + plates.Add(theEntry.FileName, memstream); + } + + zipStream.Close(); + + foreach (var loop in loops) + Nest.Loops.Add(ReadLoop(loop.Key, loop.Value)); + + Nest.ResolveLoops(); + + foreach (var plate in plates) + Nest.Plates.Add(ReadPlate(plate.Key, plate.Value)); + } + + public void Read(string nestFile) + { + if (!File.Exists(nestFile)) + { + var msg = string.Format("File Not Found: {0}", nestFile); + throw new FileNotFoundException(msg); + } + + Stream stream = null; + + try + { + stream = new FileStream(nestFile, FileMode.Open); + Read(stream); + } + finally + { + if (stream != null) + stream.Close(); + } + } + + private void LoadInfo(Stream stream) + { + try + { + Nest.Info = NestInfo.Load(stream); + } + catch (Exception exception) + { + Debug.WriteLine(exception.Message); + Debug.WriteLine(exception.StackTrace); + } + } + + private void LoadReport(Stream stream) + { + try + { + Nest.Report = Report.Load(stream); + } + catch (Exception exception) + { + Debug.WriteLine(exception.Message); + Debug.WriteLine(exception.StackTrace); + } + } + + private void LoadDrawingInfo(Stream stream) + { + var reader = new BinaryReader(stream); + var buffer = new byte[2000]; + + while (stream.Read(buffer, 0, buffer.Length) > 0) + { + var name = Encoding.Default.GetString(buffer, 200, 200); + var qty = BitConverter.ToInt32(buffer, 432); + var drawing = new NestDrawing(); + + drawing.Name = Encoding.Default.GetString(buffer, 200, 200).Trim(); + drawing.QtyRequired = BitConverter.ToInt32(buffer, 432); + Nest.Drawings.Add(drawing); + } + } + + private Loop ReadLoop(string name, Stream stream) + { + var reader = new LoopReader(); + reader.Read(name, stream); + + return reader.Loop; + } + + private Plate ReadPlate(string name, Stream stream) + { + var reader = new PlateReader(); + reader.Read(name, stream, Nest); + + return reader.Plate; + } + } +} diff --git a/PepLib/IO/PlateReader.cs b/PepLib/IO/PlateReader.cs new file mode 100644 index 0000000..b8244d3 --- /dev/null +++ b/PepLib/IO/PlateReader.cs @@ -0,0 +1,322 @@ +using System.IO; +using PepLib.Codes; + +namespace PepLib.IO +{ + internal sealed class PlateReader + { + public Plate Plate { get; private set; } + + public PlateReader() + { + Plate = new Plate(); + Plate.Duplicates = 1; + } + + public PlateReader(Plate plate) + { + Plate = plate; + } + + public void Read(string name, Stream stream, Nest nest) + { + var pos = new Vector(0, 0); + var pgm = Program.Load(stream); + + Plate.Name = name; + + foreach (var code in pgm) + { + switch (code.CodeType()) + { + case CodeType.CircularMove: + { + var arc = (CircularMove)code; + pos = arc.EndPoint; + break; + } + + case CodeType.LinearMove: + { + var line = (LinearMove)code; + pos = line.EndPoint; + break; + } + + case CodeType.RapidMove: + { + var rapid = (RapidMove)code; + pos = rapid.EndPoint; + break; + } + + case CodeType.Comment: + { + var comment = (Comment)code; + LoadInfo(comment.Value); + break; + } + + case CodeType.SubProgramCall: + { + var subpgm = (SubProgramCall)code; + var loop = nest.GetLoop(subpgm.LoopId); + var part = Part.Create(loop, pos, AngleConverter.ToRadians(subpgm.Rotation)); + Plate.Parts.Add(part); + break; + } + } + } + } + + private void LoadInfo(string value) + { + if (value.StartsWith("POSTED FILES")) + ParsePostedFiles(value); + + else if (value.StartsWith("HEAT LOT")) + ParseHeatLot(value); + + else if (value.StartsWith("SPACING")) + ParseSpacing(value); + + else if (value.StartsWith("CUT A TOTAL OF ")) + ParseNumberOfDuplicates(value); + + else if (value.StartsWith("EDGES,")) + ParseEdgeSpacing(value); + + else if (value.StartsWith("PLATE SCALING")) + ParsePlateSize(value); + + else if (value.StartsWith("MACHINE")) + ParseMachine(value); + + else if (value.StartsWith("MATERIAL")) + ParseMaterial(value); + + else if (value.StartsWith("GRADE")) + ParseGrade(value); + + else if (value.StartsWith("DESCRIPTION")) + ParseDescription(value); + + else if (value.StartsWith("PLATE THICKNESS")) + ParseThickness(value); + + else if (value.StartsWith("DENSITY")) + ParseDensity(value); + + else if (value.StartsWith("TORCHES")) + ParseTorchCount(value); + } + + private void ParseNumberOfDuplicates(string data) + { + var parts = data.Split(' '); + + if (parts.Length != 7) + return; + + int dup; + int.TryParse(parts[4], out dup); + + Plate.Duplicates = dup; + } + + private void ParsePostedFiles(string data) + { + if (data.Length < 14) + return; + + Plate.PostedFiles = data.Remove(0, 14).Trim(); + } + + private void ParseHeatLot(string data) + { + if (data.Length < 9) + return; + + Plate.HeatLot = data.Remove(0, 9).Trim(); + } + + private void ParseSpacing(string data) + { + var parts = data.Split('='); + + if (parts.Length != 2) + return; + + double spacing; + double.TryParse(parts[1], out spacing); + + Plate.PartSpacing = spacing; + } + + private void ParseEdgeSpacing(string data) + { + var parts = data.Split(','); + + if (parts.Length != 5) + return; + + var leftSplit = parts[1].Split('='); + if (leftSplit.Length == 2) + { + double x; + double.TryParse(leftSplit[1], out x); + Plate.EdgeSpacing.Left = x; + } + + var bottomSplit = parts[2].Split('='); + if (bottomSplit.Length == 2) + { + double x; + double.TryParse(bottomSplit[1], out x); + Plate.EdgeSpacing.Bottom = x; + } + + var rightSplit = parts[3].Split('='); + if (rightSplit.Length == 2) + { + double x; + double.TryParse(rightSplit[1], out x); + Plate.EdgeSpacing.Right = x; + } + + var topSplit = parts[4].Split('='); + if (topSplit.Length == 2) + { + double x; + double.TryParse(topSplit[1], out x); + Plate.EdgeSpacing.Top = x; + } + } + + private void ParsePlateSize(string data) + { + var quadrantIndex = data.IndexOf("QUADRANT"); + + if (quadrantIndex != -1) + { + var plateData = data.Remove(quadrantIndex); + var plateDataSplit = plateData.Split('='); + if (plateDataSplit.Length == 2) + { + Size plateSize; + Size.TryParse(plateDataSplit[1], out plateSize); + Plate.Size = plateSize; + } + + var quadrantData = data.Remove(0, quadrantIndex); + var quadrantDataSplit = quadrantData.Split('='); + if (quadrantDataSplit.Length == 2) + { + int quadrant; + int.TryParse(quadrantDataSplit[1], out quadrant); + Plate.Quadrant = quadrant; + } + } + else + { + var plateDataSplit = data.Split('='); + if (plateDataSplit.Length == 2) + { + Size plateSize; + Size.TryParse(plateDataSplit[1], out plateSize); + Plate.Size = plateSize; + } + } + } + + private void ParseMachine(string data) + { + var parts = data.Split(','); + + if (parts.Length != 2) + return; + + var machineSplit = parts[0].Split('='); + if (machineSplit.Length == 2) + { + int num; + int.TryParse(machineSplit[1], out num); + Plate.Machine.Id = num; + } + + Plate.Machine.Name = parts[1].Trim(); + } + + private void ParseMaterial(string data) + { + var parts = data.Split('='); + + if (parts.Length != 2) + return; + + int material; + int.TryParse(parts[1], out material); + + Plate.Material.Id = material; + } + + private void ParseGrade(string data) + { + var parts = data.Split('='); + + if (parts.Length != 2) + return; + + Plate.Material.Grade = parts[1].Trim(); + } + + private void ParseDescription(string data) + { + var parts = data.Split('='); + + if (parts.Length != 2) + return; + + Plate.Description = parts[1].Trim(); + } + + private void ParseThickness(string data) + { + var parts = data.Split('='); + + if (parts.Length != 2) + return; + + double thickness; + double.TryParse(parts[1], out thickness); + + Plate.Thickness = thickness; + } + + private void ParseDensity(string data) + { + var parts = data.Split('='); + + if (parts.Length != 2) + return; + + double density; + double.TryParse(parts[1], out density); + + Plate.Material.Density = density; + } + + private void ParseTorchCount(string data) + { + var parts = data.Split('='); + + if (parts.Length != 2) + return; + + int torchCount; + int.TryParse(parts[1], out torchCount); + + Plate.TorchCount = torchCount; + } + } +} \ No newline at end of file diff --git a/PepLib/IO/ProgramReader.cs b/PepLib/IO/ProgramReader.cs new file mode 100644 index 0000000..f80a0d7 --- /dev/null +++ b/PepLib/IO/ProgramReader.cs @@ -0,0 +1,404 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using PepLib.Codes; + +namespace PepLib.IO +{ + internal sealed class ProgramReader + { + private const int BufferSize = 200; + private int codeIndex; + private CodeBlock block; + private CodeSection section; + + public Program Program { get; private set; } + + public ProgramReader() + { + Program = new Program(); + } + + public ProgramReader(Program program) + { + Program = program; + } + + public void Read(Stream stream) + { + foreach (var line in GetLines(stream)) + { + block = ParseBlock(line); + ProcessCurrentBlock(); + } + } + + private IEnumerable GetLines(Stream stream) + { + var buffer = new byte[BufferSize]; + + while (stream.Read(buffer, 0, BufferSize) > 0) + { + yield return Encoding.ASCII.GetString(buffer); + } + } + + private CodeBlock ParseBlock(string line) + { + var block = new CodeBlock(); + Code code = null; + + for (int i = 0; i < line.Length; ++i) + { + var c = line[i]; + + if (char.IsLetter(c)) + block.Add((code = new Code(c))); + else if (c == ':') + { + block.Add((new Code(c, line.Remove(0, i + 1).Trim()))); + break; + } + else if (code != null) + code.Value += c; + } + + return block; + } + + private void ProcessCurrentBlock() + { + var code = GetFirstCode(); + + while (code != null) + { + switch (code.Id) + { + case ':': + Program.Add(new Comment(code.Value)); + code = GetNextCode(); + break; + + case 'G': + int value = int.Parse(code.Value); + + switch (value) + { + case 0: + case 1: + section = CodeSection.Line; + ReadLine(value == 0); + code = GetCurrentCode(); + break; + + case 2: + case 3: + section = CodeSection.Arc; + ReadArc(value == 2 ? RotationType.CW : RotationType.CCW); + code = GetCurrentCode(); + break; + + case 92: + section = CodeSection.SubProgram; + ReadSubProgram(); + code = GetCurrentCode(); + break; + + case 40: + Program.Add(new SetKerf() { Kerf = KerfType.None }); + code = GetNextCode(); + break; + + case 41: + Program.Add(new SetKerf() { Kerf = KerfType.Left }); + code = GetNextCode(); + break; + + case 42: + Program.Add(new SetKerf() { Kerf = KerfType.Right }); + code = GetNextCode(); + break; + + default: + code = GetNextCode(); + break; + } + break; + + case 'F': + Program.Add(new SetFeedrate() { Value = double.Parse(code.Value) }); + code = GetNextCode(); + break; + + default: + code = GetNextCode(); + break; + } + } + } + + private void ReadLine(bool isRapid) + { + double x = 0; + double y = 0; + var type = EntityType.Cut; + + while (section == CodeSection.Line) + { + var code = GetNextCode(); + + if (code == null) + { + section = CodeSection.Unknown; + break; + } + + switch (code.Id) + { + case 'X': + x = double.Parse(code.Value); + break; + + case 'Y': + y = double.Parse(code.Value); + break; + + case ':': + { + var value = code.Value.Trim().ToUpper(); + + switch (value) + { + case "EXTERNAL LEAD-IN": + type = EntityType.ExternalLeadin; + break; + + case "EXTERNAL LEAD-OUT": + type = EntityType.ExternalLeadout; + break; + + case "INTERNAL LEAD-IN": + type = EntityType.InternalLeadin; + break; + + case "INTERNAL LEAD-OUT": + type = EntityType.InternalLeadout; + break; + + case "DISPLAY": + type = EntityType.Display; + break; + } + break; + } + + default: + section = CodeSection.Unknown; + break; + } + } + + if (isRapid) + Program.Add(new RapidMove(x, y)); + else + Program.Add(new LinearMove(x, y) { Type = type }); + } + + private void ReadArc(RotationType rotation) + { + double x = 0; + double y = 0; + double i = 0; + double j = 0; + var type = EntityType.Cut; + + while (section == CodeSection.Arc) + { + var code = GetNextCode(); + + if (code == null) + { + section = CodeSection.Unknown; + break; + } + + switch (code.Id) + { + case 'X': + x = double.Parse(code.Value); + break; + + case 'Y': + y = double.Parse(code.Value); + break; + + case 'I': + i = double.Parse(code.Value); + break; + + case 'J': + j = double.Parse(code.Value); + break; + + case ':': + { + var value = code.Value.Trim().ToUpper(); + + switch (value) + { + case "EXTERNAL LEAD-IN": + type = EntityType.ExternalLeadin; + break; + + case "EXTERNAL LEAD-OUT": + type = EntityType.ExternalLeadout; + break; + + case "INTERNAL LEAD-IN": + type = EntityType.InternalLeadin; + break; + + case "INTERNAL LEAD-OUT": + type = EntityType.InternalLeadout; + break; + + case "DISPLAY": + type = EntityType.Display; + break; + } + break; + } + + default: + section = CodeSection.Unknown; + break; + } + } + + Program.Add(new CircularMove() + { + EndPoint = new Vector(x, y), + CenterPoint = new Vector(i, j), + Rotation = rotation, + Type = type + }); + } + + private void ReadSubProgram() + { + int l = 0; + int r = 0; + double p = 0; + + while (section == CodeSection.SubProgram) + { + var code = GetNextCode(); + + if (code == null) + { + section = CodeSection.Unknown; + break; + } + + switch (code.Id) + { + case 'L': + l = int.Parse(code.Value); + break; + + case 'R': + r = int.Parse(code.Value); + break; + + case 'P': + p = double.Parse(code.Value); + break; + + default: + section = CodeSection.Unknown; + break; + } + } + + Program.Add(new SubProgramCall() { LoopId = l, RepeatCount = r, Rotation = p }); + } + + private Code GetNextCode() + { + codeIndex++; + + if (codeIndex >= block.Count) + return null; + + return block[codeIndex]; + } + + private Code GetCurrentCode() + { + if (codeIndex >= block.Count) + return null; + + return block[codeIndex]; + } + + private Code GetFirstCode() + { + if (block.Count == 0) + return null; + + codeIndex = 0; + + return block[codeIndex]; + } + + private class Code + { + public Code(char id) + { + Id = id; + Value = string.Empty; + } + + public Code(char id, string value) + { + Id = id; + Value = value; + } + + public char Id { get; private set; } + + public string Value { get; set; } + + public override string ToString() + { + return Id + Value; + } + } + + private class CodeBlock : List + { + public void Add(char id, string value) + { + Add(new Code(id, value)); + } + + public override string ToString() + { + var builder = new StringBuilder(); + + foreach (var code in this) + builder.Append(code.ToString() + " "); + + return builder.ToString(); + } + } + + private enum CodeSection + { + Unknown, + Arc, + Line, + SubProgram + } + } +} diff --git a/PepLib/IO/ReportReader.cs b/PepLib/IO/ReportReader.cs new file mode 100644 index 0000000..c2d39c7 --- /dev/null +++ b/PepLib/IO/ReportReader.cs @@ -0,0 +1,378 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace PepLib.IO +{ + internal sealed class ReportReader + { + public Report Report { get; private set; } + + public ReportReader() + { + Report = new Report(); + } + + public ReportReader(Report report) + { + Report = report; + } + + public void Read(Stream stream) + { + var reader = new StreamReader(stream); + + Report.Drawing dwg = null; + Report.Plate plt = null; + + var section = Section.Unknown; + + string line; + + while ((line = reader.ReadLine()) != null) + { + var equalIndex = line.IndexOf('='); + + if (equalIndex != -1) + { + var valueIndex = equalIndex + 1; + var key = line.Substring(0, equalIndex).Trim(); + var value = line.Substring(valueIndex, line.Length - valueIndex).Trim(); + + switch (section) + { + case Section.NestHeader: + ReadNestHeaderData(key, value); + break; + + case Section.NestedPlates: + ReadNestedPlatesData(key, value, plt); + break; + + case Section.QuantitiesNested: + ReadQuantitiesNestedData(key, value, dwg); + break; + + case Section.Unknown: + break; + } + } + else + { + var category = line.Trim(); + + switch (category) + { + case "Nest header": + section = Section.NestHeader; + continue; + case "Nested plates": + section = Section.NestedPlates; + continue; + case "Quantities nested": + section = Section.QuantitiesNested; + continue; + } + + switch (section) + { + case Section.NestedPlates: + if (category.StartsWith("Plate")) + Report.Plates.Add((plt = new Report.Plate())); + break; + + case Section.QuantitiesNested: + if (category.StartsWith("Drawing")) + Report.Drawings.Add((dwg = new Report.Drawing())); + break; + + default: + Debug.WriteLine("Unknown category: " + category); + break; + } + } + } + } + + public void Read(string nestFile) + { + if (!File.Exists(nestFile)) + { + var msg = string.Format("File Not Found: {0}", nestFile); + throw new FileNotFoundException(msg); + } + + Stream stream = null; + string name; + + try + { + ZipHelper.ExtractByExtension(nestFile, ".report", out name, out stream); + Read(stream); + } + finally + { + if (stream != null) + stream.Close(); + } + } + + private void ReadNestHeaderData(string key, string value) + { + switch (key) + { + case "Program": + Report.Name = value; + break; + + case "Customer name": + Report.Customer = value; + break; + + case "Date programmed": + DateTime date; + DateTime.TryParse(value, out date); + Report.DateProgrammed = date; + break; + + case "Material": + Report.Material = value; + break; + + case "Programmed by": + Report.ProgrammedBy = value; + break; + + case "Machine": + Report.Machine = value; + break; + + case "Comments": + Report.Comments = value; + break; + + case "Remarks": + Report.Remarks = value; + break; + + default: + Debug.WriteLine(string.Format("Report.ReadNestHeaderData: \"{0}\" not implemented", key)); + break; + } + } + + private void ReadNestedPlatesData(string key, string value, Report.Plate plt) + { + switch (key) + { + case "Plate number": + plt.Name = value; + break; + + case "Thickness": + plt.Thickness = ParseDouble(value); + break; + + case "Plate Size": + ReadPlateSize(value, plt); + break; + + case "Material": + plt.MaterialNumber = ParseInt32(value); + break; + + case "Grade": + plt.MaterialGrade = value; + break; + + case "Material Description": + plt.MaterialDescription = value; + break; + + case "Dup plates": + plt.Quantity = int.Parse(value); + break; + + case "Plate Util": + plt.PlateUtilization = ParsePercent(value); + break; + + case "Material Util": + plt.MaterialUtilization = ParsePercent(value); + break; + + case "Total Area1": + plt.Area1 = ParseDouble(value); + break; + + case "Total Area2": + plt.Area2 = ParseDouble(value); + break; + + case "Bubble pierces": + plt.BubblePierceCount = ParseInt32(value); + break; + + case "Total cutting time": + ReadCuttingTime(value, Report); + break; + + case "Cutting feedrate": + Report.CutFeedrate = ParseInt32(value); + break; + + case "Rapid feedrate": + Report.RapidFeedrate = ParseInt32(value); + break; + + default: + Debug.WriteLine(string.Format("Report.ReadNestedPlatesData: \"{0}\" not implemented", key)); + break; + } + } + + private void ReadQuantitiesNestedData(string key, string value, Report.Drawing dwg) + { + switch (key) + { + case "Customer Name": + dwg.Customer = value; + break; + + case "Drawing Name": + dwg.Name = value; + break; + + case "Revision": + dwg.Revision = value; + break; + + case "Qty Req": + dwg.QtyRequired = ParseInt32(value); + break; + + case "Qty Nstd": + dwg.QtyNested = ParseInt32(value); + break; + + case "# of Pierces": + dwg.PierceCount = ParseInt32(value); + break; + + case "Intersections": + dwg.IntersectionCount = ParseInt32(value); + break; + + case "Area1*": + dwg.Area1 = ParseDouble(value); + break; + + case "Area2**": + dwg.Area2 = ParseDouble(value); + break; + + case "% of Material": + dwg.PercentOfMaterial = ParsePercent(value); + break; + + case "% of Time": + dwg.PercentOfCutTime = ParsePercent(value); + dwg.TotalCutTime = + TimeSpan.FromTicks((long)(Report.TotalCutTime.Ticks * dwg.PercentOfCutTime / 100.0)); + break; + + default: + Debug.WriteLine(string.Format("Report.ReadQuantitiesNestedData: \"{0}\" not implemented", key)); + break; + } + } + + private void ReadPlateSize(string value, Report.Plate plt) + { + var a = value.ToUpper().Split('X'); + + var x = float.Parse(a[0]); + var y = float.Parse(a[1]); + + if (x < y) + { + plt.Width = x; + plt.Length = y; + } + else + { + plt.Width = y; + plt.Length = x; + } + } + + private void ReadCuttingTime(string value, Report report) + { + var parts = value.Split(','); + + int hrs = 0, min = 0, sec = 0; + + foreach (var part in parts) + { + if (part.Contains("hr")) + hrs = int.Parse(part.Remove(part.IndexOf("hr"))); + + else if (part.Contains("min")) + min = int.Parse(part.Remove(part.IndexOf("min"))); + + else if (part.Contains("sec")) + sec = int.Parse(part.Remove(part.IndexOf("sec"))); + } + + report.TotalCutTime = new TimeSpan(hrs, min, sec); + } + + private static double ParsePercent(string s, double defaultValue = 0.0) + { + var t = s.TrimEnd('%', ' '); + double f; + + if (!double.TryParse(t, out f)) + { + Debug.WriteLine("Failed to convert \"" + s + "\" from percent string to double"); + return defaultValue; + } + + return f; + } + + private static double ParseDouble(string s, double defaultValue = 0.0) + { + double f; + + if (!double.TryParse(s, out f)) + { + Debug.WriteLine("Failed to convert \"" + s + "\" from string to double"); + return defaultValue; + } + + return f; + } + + private static int ParseInt32(string s, int defaultValue = 0) + { + int i; + + if (!int.TryParse(s, out i)) + { + Debug.WriteLine("Failed to convert \"" + s + "\" from string to int"); + return defaultValue; + } + + return i; + } + + private enum Section + { + Unknown, + NestHeader, + NestedPlates, + QuantitiesNested, + } + } +} diff --git a/PepLib/IniConfig.cs b/PepLib/IniConfig.cs new file mode 100644 index 0000000..76e2e34 --- /dev/null +++ b/PepLib/IniConfig.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace PepLib +{ + public class IniConfig + { + public List Nodes; + + public IniConfig() + { + Nodes = new List(); + } + + private static int LeadingWhitespaceCount(string s) + { + for (int i = 0; i < s.Length; ++i) + if (s[i] != ' ') return i; + + return 0; + } + + public Node FindNode(string path) + { + return FindNode(path, Nodes); + } + + private Node FindNode(string path, List nodes) + { + var a = path.Split('/'); + + var b = nodes.FirstOrDefault(node => + { + if (node is KeyNode) + { + var c = node as KeyNode; + return c.Name.ToUpper() == a[0].ToUpper(); + } + else + { + return node.Value == a[0].Trim(); + } + }); + + string path2 = string.Empty; + + for (int i = 1; i < a.Length; ++i) + path2 += a[i] + '/'; + + if (b == null || a.Length == 1) + return b; + else + return FindNode(path2.TrimEnd('/'), b.Children); + } + + public static IniConfig Load(string file) + { + var doc = new IniConfig(); + var reader = new StreamReader(file); + + Node currentNode = null; + string line; + + while ((line = reader.ReadLine()) != null) + { + int spaces = LeadingWhitespaceCount(line) / 2; + var node = new Node(); + node.Value = line.Trim(); + + var keyNode = KeyNode.Parse(node); + + if (keyNode != null) + node = keyNode; + + int currentdepth = currentNode != null ? currentNode.Level : 0; + + if (spaces == 0) + doc.Nodes.Add(node); + else if (spaces == currentdepth) + currentNode.Parent.AddChild(node); + else if (spaces > currentdepth) + currentNode.AddChild(node); + else if (spaces < currentdepth) + { + var n = currentNode.Parent; + + while (spaces < n.Level) + n = n.Parent; + + n.Parent.AddChild(node); + } + + currentNode = node; + } + + reader.Close(); + + return doc; + } + } +} diff --git a/PepLib/KerfType.cs b/PepLib/KerfType.cs new file mode 100644 index 0000000..90e9b53 --- /dev/null +++ b/PepLib/KerfType.cs @@ -0,0 +1,10 @@ + +namespace PepLib +{ + public enum KerfType + { + None, + Left, + Right + } +} diff --git a/PepLib/Loop.cs b/PepLib/Loop.cs new file mode 100644 index 0000000..01b2975 --- /dev/null +++ b/PepLib/Loop.cs @@ -0,0 +1,57 @@ +using System; +using PepLib.Codes; + +namespace PepLib +{ + public class Loop : Program + { + public Loop() + { + Mode = ProgrammingMode.Incremental; + } + + public string Name { get; set; } + + public Vector ReferencePoint { get; set; } + + public DateTime LastReferenceDate { get; set; } + + public string DrawingName { get; set; } + + public string DxfPath { get; set; } + + public override void Rotate(double angle) + { + base.Rotate(angle); + ReferencePoint = ReferencePoint.Rotate(angle); + } + + public override void Rotate(double angle, Vector origin) + { + base.Rotate(angle, origin); + ReferencePoint = ReferencePoint.Rotate(angle); + } + + public object Clone() + { + var loop = new Loop() + { + Name = this.Name, + ReferencePoint = this.ReferencePoint, + LastReferenceDate = this.LastReferenceDate, + DrawingName = this.DrawingName, + DxfPath = this.DxfPath, + Rotation = this.Rotation + }; + + var codes = new ICode[this.Count]; + + for (int i = 0; i < this.Count; ++i) + codes[i] = this[i].Clone(); + + loop.AddRange(codes); + + return loop; + } + } +} diff --git a/PepLib/Machine.cs b/PepLib/Machine.cs new file mode 100644 index 0000000..8fbb0c7 --- /dev/null +++ b/PepLib/Machine.cs @@ -0,0 +1,9 @@ +namespace PepLib +{ + public class Machine + { + public int Id { get; set; } + + public string Name { get; set; } + } +} diff --git a/PepLib/Material.cs b/PepLib/Material.cs new file mode 100644 index 0000000..e219c2d --- /dev/null +++ b/PepLib/Material.cs @@ -0,0 +1,11 @@ +namespace PepLib +{ + public class Material + { + public int Id { get; set; } + + public string Grade { get; set; } + + public double Density { get; set; } + } +} diff --git a/PepLib/MathHelper.cs b/PepLib/MathHelper.cs new file mode 100644 index 0000000..70071ee --- /dev/null +++ b/PepLib/MathHelper.cs @@ -0,0 +1,55 @@ +using System; + +namespace PepLib +{ + public static class MathHelper + { + public const double HalfPI = Math.PI * 0.5; + public const double TwoPI = Math.PI * 2.0; + + public static double NormalizeAngleRad(double angle) + { + double r = angle % TwoPI; + return r < 0 ? TwoPI + r : r; + } + + public static double NormalizeAngleDeg(double angle) + { + double r = angle % 360.0; + return r < 0 ? 360.0 + r : r; + } + + public static bool IsAngleBetween(double angle, double a1, double a2, bool reversed = false) + { + if (reversed) + Generic.Swap(ref a1, ref a2); + + var diff = NormalizeAngleRad(a2 - a1); + + // full circle + if (a2.IsEqualTo(a1)) + return true; + + a1 = NormalizeAngleRad(angle - a1); + a2 = NormalizeAngleRad(a2 - angle); + + return diff >= a1 - Tolerance.Epsilon || + diff >= a2 - Tolerance.Epsilon; + } + + public static double RoundDownToNearest(double num, double factor) + { + return factor == 0 ? num : Math.Floor(num / factor) * factor; + } + + public static double RoundUpToNearest(double num, double factor) + { + return factor == 0 ? num : Math.Ceiling(num / factor) * factor; + } + + public static double RoundToNearest(double num, double factor) + { + return factor == 0 ? num : Math.Round(num / factor) * factor; + } + } +} diff --git a/PepLib/Nest.cs b/PepLib/Nest.cs new file mode 100644 index 0000000..9fbb7b3 --- /dev/null +++ b/PepLib/Nest.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.IO; +using PepLib.Codes; +using PepLib.IO; + +namespace PepLib +{ + public class Nest + { + public Nest() + { + Info = new NestInfo(); + Report = new Report(); + Loops = new List(); + Plates = new List(); + Drawings = new List(); + } + + public NestInfo Info { get; set; } + + public Report Report { get; set; } + + public List Loops { get; set; } + + public List Plates { get; set; } + + public List Drawings { get; set; } + + public void ResolveLoops() + { + for (int i = 0; i < Loops.Count; ++i) + { + var loop = Loops[i]; + ResolveLoops(loop); + } + } + + private void ResolveLoops(Program pgm) + { + for (int i = 0; i < pgm.Count; ++i) + { + var code = pgm[i]; + + if (code.CodeType() != CodeType.SubProgramCall) + continue; + + var subpgmcall = (SubProgramCall)code; + + var loop = GetLoop(subpgmcall.LoopId); + + if (loop == null) + throw new Exception("Loop not found"); + + subpgmcall.Loop = loop; + } + } + + public int GetQtyNested(string drawing) + { + int qty = 0; + + foreach (var plate in Plates) + qty += plate.GetQtyNested(drawing); + + return qty; + } + + private string GetLoopName(int loopId) + { + return string.Format("{0}.loop-{1}", Info.Name, loopId.ToString().PadLeft(3, '0')); + } + + private Loop GetLoop(string name) + { + for (int i = 0; i < Loops.Count; ++i) + { + if (Loops[i].Name == name) + return Loops[i]; + } + + return null; + } + + public Loop GetLoop(int id) + { + string name = GetLoopName(id); + return GetLoop(name); + } + + public static Nest Load(string nestfile) + { + var reader = new NestReader(); + reader.Read(nestfile); + return reader.Nest; + } + + public static Nest Load(Stream stream) + { + var reader = new NestReader(); + reader.Read(stream); + return reader.Nest; + } + + public static bool TryLoad(string nestfile, out Nest nest) + { + try + { + nest = Load(nestfile); + } + catch (Exception) + { + nest = null; + return false; + } + + return true; + } + + public static bool TryLoad(Stream stream, out Nest nest) + { + try + { + nest = Load(stream); + } + catch (Exception) + { + nest = null; + return false; + } + + return true; + } + + #region NestInfo wrapper properties + + public string Name + { + get { return Info.Name; } + set { Info.Name = value; } + } + + public DateTime CreationDate + { + get { return Info.DateCreated; } + set { Info.DateCreated = value; } + } + + public DateTime LastModifiedDate + { + get { return Info.DateLastModified; } + set { Info.DateLastModified = value; } + } + + public StatusType Status + { + get { return Info.Status; } + set { Info.Status = value; } + } + + public int LoopCount + { + get { return Info.LoopCount; } + set { Info.LoopCount = value; } + } + + public int PlateCount + { + get { return Info.PlateCount; } + set { Info.PlateCount = value; } + } + + public string Comment + { + get { return Info.Comments; } + set { Info.Comments = value; } + } + + public string Customer + { + get { return Info.Customer; } + set { Info.Customer = value; } + } + + public string ProgrammedBy + { + get { return Info.ProgrammedBy; } + set { Info.ProgrammedBy = value; } + } + + public int MaterialNumber + { + get { return Info.MaterialNumber; } + set { Info.MaterialNumber = value; } + } + + public string MaterialGrade + { + get { return Info.MaterialGrade; } + set { Info.MaterialGrade = value; } + } + + public string Notes + { + get { return Info.Notes; } + set { Info.Notes = value; } + } + + public string DefaultPlateSize + { + get { return Info.DefaultPlateSize; } + set { Info.DefaultPlateSize = value; } + } + + public string Kerf + { + get { return Info.Kerf; } + set { Info.Kerf = value; } + } + + public string PostedAs + { + get { return Info.PostedAs; } + set { Info.PostedAs = value; } + } + + public string Errors + { + get { return Info.Errors; } + set { Info.Errors = value; } + } + + public string UserDefined1 + { + get { return Info.UserDefined1; } + set { Info.UserDefined1 = value; } + } + + public string UserDefined2 + { + get { return Info.UserDefined2; } + set { Info.UserDefined2 = value; } + } + + public string UserDefined3 + { + get { return Info.UserDefined3; } + set { Info.UserDefined3 = value; } + } + + public string UserDefined4 + { + get { return Info.UserDefined4; } + set { Info.UserDefined4 = value; } + } + + public string UserDefined5 + { + get { return Info.UserDefined5; } + set { Info.UserDefined5 = value; } + } + + public string UserDefined6 + { + get { return Info.UserDefined6; } + set { Info.UserDefined6 = value; } + } + + #endregion + } +} diff --git a/PepLib/NestDrawing.cs b/PepLib/NestDrawing.cs new file mode 100644 index 0000000..f87e946 --- /dev/null +++ b/PepLib/NestDrawing.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PepLib +{ + public class NestDrawing + { + public string Name { get; set; } + + public int QtyRequired { get; set; } + } +} diff --git a/PepLib/NestIndex.cs b/PepLib/NestIndex.cs new file mode 100644 index 0000000..db20694 --- /dev/null +++ b/PepLib/NestIndex.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using PepLib.IO; + +namespace PepLib +{ + public class NestIndex + { + public string Directory { get; set; } + + public List Entries; + + public NestIndex() + { + Entries = new List(); + } + + public string GetPath(NestInfo entry) + { + return Path.Combine(Directory, entry.Name + ".zip"); + } + + public static NestIndex LoadFromDir(string directory) + { + var file = Path.Combine(directory, "pepfiles.lfn"); + return Load(file); + } + + public static NestIndex Load(string file) + { + if (!File.Exists(file)) + return null; + + var index = new NestIndex() { Directory = Path.GetDirectoryName(file) }; + var stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + var reader = new StreamReader(stream); + var buffer = new char[4000]; + + while (reader.Read(buffer, 0, buffer.Length) > 0) + { + var memstream = new MemoryStream(Encoding.Default.GetBytes(buffer)); + var inforeader = new NestInfoReader(); + + inforeader.Read(memstream); + index.Entries.Add(inforeader.Info); + } + + reader.Close(); + + return index; + } + + public static NestIndex Build(string directory) + { + var index = new NestIndex() { Directory = directory }; + + foreach (var file in System.IO.Directory.GetFiles(directory, "*.zip")) + { + var reader = new NestInfoReader(); + reader.Read(file); + index.Entries.Add(reader.Info); + } + + return index; + } + } +} diff --git a/PepLib/NestInfo.cs b/PepLib/NestInfo.cs new file mode 100644 index 0000000..231dd6b --- /dev/null +++ b/PepLib/NestInfo.cs @@ -0,0 +1,99 @@ +using System; +using System.IO; +using PepLib.IO; + +namespace PepLib +{ + public class NestInfo + { + public string Name { get; set; } + + public DateTime DateCreated { get; set; } + + public DateTime DateLastModified { get; set; } + + public StatusType Status { get; set; } + + public int LoopCount { get; set; } + + public int ProgramCount { get; set; } + + public int PlateCount { get; set; } + + public string Comments { get; set; } + + public string Customer { get; set; } + + public string ProgrammedBy { get; set; } + + public int MaterialNumber { get; set; } + + public string MaterialGrade { get; set; } + + public string Notes { get; set; } + + public string DefaultPlateSize { get; set; } + + public string Kerf { get; set; } + + public string PostedAs { get; set; } + + public string Errors { get; set; } + + public string UserDefined1 { get; set; } + + public string UserDefined2 { get; set; } + + public string UserDefined3 { get; set; } + + public string UserDefined4 { get; set; } + + public string UserDefined5 { get; set; } + + public string UserDefined6 { get; set; } + + public static NestInfo Load(string nestFile) + { + var reader = new NestInfoReader(); + reader.Read(nestFile); + return reader.Info; + } + + public static NestInfo Load(Stream stream) + { + var reader = new NestInfoReader(); + reader.Read(stream); + return reader.Info; + } + + public static bool TryLoad(string nestFile, out NestInfo nestInfo) + { + try + { + nestInfo = Load(nestFile); + } + catch (Exception) + { + nestInfo = null; + return false; + } + + return true; + } + + public static bool TryLoad(Stream stream, out NestInfo nestInfo) + { + try + { + nestInfo = Load(stream); + } + catch (Exception) + { + nestInfo = null; + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/PepLib/Node.cs b/PepLib/Node.cs new file mode 100644 index 0000000..1ee9070 --- /dev/null +++ b/PepLib/Node.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace PepLib +{ + public class Node + { + private Node parent; + + public List Children; + + public Node() + { + Children = new List(); + } + + public Node Parent + { + get { return parent; } + set + { + parent = value; + UpdateDepth(); + } + } + + public string Value { get; set; } + + private void UpdateDepth() + { + if (Parent != null) + Level = Parent.Level + 1; + else + Level = 0; + + foreach (var node in Children) + node.Parent = this; + } + + public int Level { get; protected set; } + + public void AddChild(Node node) + { + node.Parent = this; + Children.Add(node); + } + + public void Write(TextWriter writer) + { + writer.WriteLine("".PadLeft(Level * 2) + this.ToString()); + + foreach (var node in Children) + node.Write(writer); + } + + public override string ToString() + { + return Value; + } + } + + public class KeyNode : Node + { + public string Name; + + public static KeyNode Parse(Node node) + { + var index = node.Value.IndexOf('='); + + if (index == -1) + return null; + + return new KeyNode() + { + Name = node.Value.Remove(index), + Value = node.Value.Remove(0, index + 1).Trim() + }; + } + + public override string ToString() + { + return string.Format("{0}={1}", Name, Value); + } + } +} diff --git a/PepLib/Part.cs b/PepLib/Part.cs new file mode 100644 index 0000000..670eb88 --- /dev/null +++ b/PepLib/Part.cs @@ -0,0 +1,123 @@ +using System; + +namespace PepLib +{ + public class Part : IMovable + { + private Loop baseLoop; + private Vector location; + + private Part() + { + BoundingBox = new Box(); + } + + public Box BoundingBox { get; protected set; } + + public Vector Location + { + get { return location; } + set + { + BoundingBox.Offset(value - location); + location = value; + } + } + + public string Name + { + get { return baseLoop.Name; } + set { baseLoop.Name = value; } + } + + /// + /// Reference point relative to the part location. + /// + public Vector ReferencePoint + { + get { return baseLoop.ReferencePoint; } + set { baseLoop.ReferencePoint = value; } + } + + /// + /// Reference point relative to the zero point. + /// + public Vector AbsoluteReferencePoint + { + get { return baseLoop.ReferencePoint + location; } + set { baseLoop.ReferencePoint = value - location; } + } + + public DateTime LastReferenceDate + { + get { return baseLoop.LastReferenceDate; } + set { baseLoop.LastReferenceDate = value; } + } + + public string DrawingName + { + get { return baseLoop.DrawingName; } + set { baseLoop.DrawingName = value; } + } + + public string DxfPath + { + get { return baseLoop.DxfPath; } + set { baseLoop.DxfPath = value; } + } + + public double Rotation + { + get { return baseLoop.Rotation; } + } + + public void Rotate(double angle) + { + baseLoop.Rotate(angle); + location = Location.Rotate(angle); + UpdateBounds(); + } + + public void Rotate(double angle, Vector origin) + { + baseLoop.Rotate(angle); + location = Location.Rotate(angle, origin); + UpdateBounds(); + } + + public void Offset(double x, double y) + { + location = new Vector(location.X + x, location.Y + y); + BoundingBox.Offset(x, y); + } + + public void Offset(Vector voffset) + { + location += voffset; + BoundingBox.Offset(voffset); + } + + public Program Program + { + get { return baseLoop; } + } + + public void UpdateBounds() + { + BoundingBox = baseLoop.GetBoundingBox(); + BoundingBox.Offset(Location); + } + + public static Part Create(Loop loop, Vector location, double rotation = 0.0) + { + var part = new Part(); + part.baseLoop = (Loop)loop.Clone(); + part.baseLoop.Mode = ProgrammingMode.Incremental; + part.baseLoop.Rotate(rotation); + part.Location = location; + part.UpdateBounds(); + + return part; + } + } +} diff --git a/PepLib/PartListExtensions.cs b/PepLib/PartListExtensions.cs new file mode 100644 index 0000000..b7f0800 --- /dev/null +++ b/PepLib/PartListExtensions.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PepLib +{ + public static class PartListExtensions + { + public static Box GetBoundingBox(this List parts) + { + if (parts.Count == 0) + return new Box(); + + var firstpart = parts[0]; + + double minX = firstpart.BoundingBox.X; + double minY = firstpart.BoundingBox.Y; + double maxX = firstpart.BoundingBox.X + firstpart.BoundingBox.Width; + double maxY = firstpart.BoundingBox.Y + firstpart.BoundingBox.Height; + + foreach (var part in parts) + { + var box = part.BoundingBox; + + if (box.Left < minX) + minX = box.Left; + + if (box.Right > maxX) + maxX = box.Right; + + if (box.Bottom < minY) + minY = box.Bottom; + + if (box.Top > maxY) + maxY = box.Top; + } + + return new Box(minX, minY, maxX - minX, maxY - minY); + } + } +} diff --git a/PepLib/PepLib.csproj b/PepLib/PepLib.csproj new file mode 100644 index 0000000..7f8096d --- /dev/null +++ b/PepLib/PepLib.csproj @@ -0,0 +1,111 @@ + + + + + Debug + AnyCPU + {22360453-B878-49FA-A5DC-0D9C577DE902} + Library + Properties + PepLib + PepLib + v4.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PepLib/Plate.cs b/PepLib/Plate.cs new file mode 100644 index 0000000..354edf8 --- /dev/null +++ b/PepLib/Plate.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PepLib +{ + public class Plate : IMovable + { + public Plate() + : this(60, 120) + { + } + + public Plate(double width, double length) + : this(new Size(width, length)) + { + } + + public Plate(Size size) + { + EdgeSpacing = new Spacing(); + Size = size; + Machine = new Machine(); + Material = new Material(); + Parts = new List(); + Quadrant = 1; + } + + public string Name { get; set; } + + public string PostedFiles { get; set; } + + public string HeatLot { get; set; } + + public double Thickness { get; set; } + + public double PartSpacing { get; set; } + + public Spacing EdgeSpacing { get; set; } + + public Size Size { get; set; } + + public Machine Machine { get; set; } + + public Material Material { get; set; } + + public List Parts { get; set; } + + public string Description { get; set; } + + public int Duplicates { get; set; } + + public int Quadrant { get; set; } + + public int TorchCount { get; set; } + + public void Rotate90CCW(bool keepSameQuadrant = true) + { + Size = new Size(Size.Width, Size.Height); + + Rotate(MathHelper.HalfPI); + + if (keepSameQuadrant) + { + switch (Quadrant) + { + case 1: + Offset(Size.Width, 0); + break; + + case 2: + Offset(0, Size.Height); + break; + + case 3: + Offset(-Size.Width, 0); + break; + + case 4: + Offset(0, -Size.Height); + break; + } + } + else + { + Quadrant = Quadrant > 3 ? 1 : Quadrant + 1; + } + } + + public void Rotate90CW(bool keepSameQuadrant = true) + { + const double oneAndHalfPI = Math.PI * 1.5; + + Size = new Size(Size.Width, Size.Height); + + Rotate(oneAndHalfPI); + + if (keepSameQuadrant) + { + switch (Quadrant) + { + case 1: + Offset(0, Size.Height); + break; + + case 2: + Offset(-Size.Width, 0); + break; + + case 3: + Offset(0, -Size.Height); + break; + + case 4: + Offset(Size.Width, 0); + break; + } + } + else + { + Quadrant = Quadrant < 2 ? 4 : Quadrant - 1; + } + } + + public void Rotate180(bool keepSameQuadrant = true) + { + if (keepSameQuadrant) + { + Vector centerpt; + + switch (Quadrant) + { + case 1: + centerpt = new Vector(Size.Width * 0.5, Size.Height * 0.5); + break; + + case 2: + centerpt = new Vector(-Size.Width * 0.5, Size.Height * 0.5); + break; + + case 3: + centerpt = new Vector(-Size.Width * 0.5, -Size.Height * 0.5); + break; + + case 4: + centerpt = new Vector(Size.Width * 0.5, -Size.Height * 0.5); + break; + + default: + return; + } + + Rotate(Math.PI, centerpt); + } + else + { + Rotate(Math.PI); + Quadrant = (Quadrant + 2) % 4; + + if (Quadrant == 0) + Quadrant = 4; + } + } + + public void Rotate(double angle) + { + for (int i = 0; i < Parts.Count; ++i) + { + var part = Parts[i]; + part.Rotate(angle); + } + } + + public void Rotate(double angle, Vector origin) + { + for (int i = 0; i < Parts.Count; ++i) + { + var part = Parts[i]; + part.Rotate(angle, origin); + } + } + + public void Offset(double x, double y) + { + for (int i = 0; i < Parts.Count; ++i) + { + var part = Parts[i]; + part.Offset(x, y); + } + } + + public void Offset(Vector voffset) + { + for (int i = 0; i < Parts.Count; ++i) + { + var part = Parts[i]; + part.Offset(voffset); + } + } + + public int GetQtyNested(string drawing) + { + var name = drawing.ToUpper(); + + return Parts.Count(p => p.DrawingName.ToUpper() == name); + } + + public Box GetBoundingBox(bool includeParts) + { + var plateBox = new Box(); + + switch (Quadrant) + { + case 1: + plateBox.X = 0; + plateBox.Y = 0; + break; + + case 2: + plateBox.X = (float)-Size.Width; + plateBox.Y = 0; + break; + + case 3: + plateBox.X = (float)-Size.Width; + plateBox.Y = (float)-Size.Height; + break; + + case 4: + plateBox.X = 0; + plateBox.Y = (float)-Size.Height; + break; + + default: + return new Box(); + } + + plateBox.Width = Size.Width; + plateBox.Height = Size.Height; + + if (!includeParts) + return plateBox; + + var boundingBox = new Box(); + var partsBox = Parts.GetBoundingBox(); + + boundingBox.X = partsBox.Left < plateBox.Left + ? partsBox.Left + : plateBox.Left; + + boundingBox.Y = partsBox.Bottom < plateBox.Bottom + ? partsBox.Bottom + : plateBox.Bottom; + + boundingBox.Width = partsBox.Right > plateBox.Right + ? partsBox.Right - boundingBox.X + : plateBox.Right - boundingBox.X; + + boundingBox.Height = partsBox.Top > plateBox.Top + ? partsBox.Top - boundingBox.Y + : plateBox.Top - boundingBox.Y; + + return boundingBox; + } + } +} diff --git a/PepLib/PlateListExtensions.cs b/PepLib/PlateListExtensions.cs new file mode 100644 index 0000000..382eb01 --- /dev/null +++ b/PepLib/PlateListExtensions.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + +namespace PepLib +{ + public static class PlateListExtensions + { + public static void JoinLikePlates(this List plates) + { + START: + + for (int i = 0; i < plates.Count; ++i) + { + var p1 = plates[i]; + + for (int j = 0; j < plates.Count; ++j) + { + var p2 = plates[j]; + + if (i == j) + continue; + + if (p1.Width != p2.Width) + continue; + + if (p1.Length != p2.Length) + continue; + + if (p1.MaterialDescription != p2.MaterialDescription) + continue; + + if (p1.Thickness != p2.Thickness) + continue; + + p1.Quantity += p2.Quantity; + plates.Remove(p2); + goto START; + } + } + } + } +} diff --git a/PepLib/Program.cs b/PepLib/Program.cs new file mode 100644 index 0000000..6eedc5a --- /dev/null +++ b/PepLib/Program.cs @@ -0,0 +1,367 @@ +using System.Collections.Generic; +using System.IO; +using PepLib.Codes; +using PepLib.IO; +using System; + +namespace PepLib +{ + public class Program : List, IMovable + { + private ProgrammingMode mode; + + public Program(ProgrammingMode mode = ProgrammingMode.Absolute) + { + Mode = mode; + } + + public ProgrammingMode Mode + { + get { return mode; } + set + { + if (value == ProgrammingMode.Absolute) + SetProgrammingModeAbs(); + else + SetProgrammingModeInc(); + } + } + + public double Rotation { get; protected set; } + + private void SetProgrammingModeInc() + { + if (mode == ProgrammingMode.Incremental) + return; + + var pos = new Vector(0, 0); + + for (int i = 0; i < Count; ++i) + { + var code = this[i]; + var motion = code as Motion; + + if (motion != null) + { + var pos2 = motion.EndPoint; + motion.Offset(-pos.X, -pos.Y); + pos = pos2; + } + } + + mode = ProgrammingMode.Incremental; + } + + private void SetProgrammingModeAbs() + { + if (mode == ProgrammingMode.Absolute) + return; + + var pos = new Vector(0, 0); + + for (int i = 0; i < Count; ++i) + { + var code = this[i]; + var motion = code as Motion; + + if (motion != null) + { + motion.Offset(pos); + pos = motion.EndPoint; + } + } + + mode = ProgrammingMode.Absolute; + } + + public virtual void Rotate(double angle) + { + var mode = Mode; + + SetProgrammingModeAbs(); + + for (int i = 0; i < Count; ++i) + { + var code = this[i]; + + if (code.CodeType() == CodeType.SubProgramCall) + { + var subpgm = (SubProgramCall)code; + + if (subpgm.Loop != null) + subpgm.Loop.Rotate(angle); + } + + if (code is IMovable == false) + continue; + + var code2 = (IMovable)code; + + code2.Rotate(angle); + } + + if (mode == ProgrammingMode.Incremental) + SetProgrammingModeInc(); + + Rotation = MathHelper.NormalizeAngleRad(Rotation + angle); + } + + public virtual void Rotate(double angle, Vector origin) + { + var mode = Mode; + + SetProgrammingModeAbs(); + + for (int i = 0; i < Count; ++i) + { + var code = this[i]; + + if (code.CodeType() == CodeType.SubProgramCall) + { + var subpgm = (SubProgramCall)code; + + if (subpgm.Loop != null) + subpgm.Loop.Rotate(angle); + } + + if (code is IMovable == false) + continue; + + var code2 = (IMovable)code; + + code2.Rotate(angle, origin); + } + + if (mode == ProgrammingMode.Incremental) + SetProgrammingModeInc(); + + Rotation = MathHelper.NormalizeAngleRad(Rotation + angle); + } + + public void Offset(double x, double y) + { + var mode = Mode; + + SetProgrammingModeAbs(); + + for (int i = 0; i < Count; ++i) + { + var code = this[i]; + + if (code is IMovable == false) + continue; + + var code2 = (IMovable)code; + + code2.Offset(x, y); + } + + if (mode == ProgrammingMode.Incremental) + SetProgrammingModeInc(); + } + + public void Offset(Vector voffset) + { + var mode = Mode; + + SetProgrammingModeAbs(); + + for (int i = 0; i < Count; ++i) + { + var code = this[i]; + + if (code is IMovable == false) + continue; + + var code2 = (IMovable)code; + + code2.Offset(voffset); + } + + if (mode == ProgrammingMode.Incremental) + SetProgrammingModeInc(); + } + + public Box GetBoundingBox() + { + var origin = new Vector(0, 0); + return GetBoundingBox(ref origin); + } + + private Box GetBoundingBox(ref Vector pos) + { + double minX = 0.0; + double minY = 0.0; + double maxX = 0.0; + double maxY = 0.0; + + for (int i = 0; i < Count; ++i) + { + var code = this[i]; + + switch (code.CodeType()) + { + case CodeType.LinearMove: + { + var line = (LinearMove)code; + var pt = Mode == ProgrammingMode.Absolute ? + line.EndPoint : + line.EndPoint + pos; + + if (pt.X > maxX) + maxX = pt.X; + else if (pt.X < minX) + minX = pt.X; + + if (pt.Y > maxY) + maxY = pt.Y; + else if (pt.Y < minY) + minY = pt.Y; + + pos = pt; + + break; + } + + case CodeType.RapidMove: + { + var line = (RapidMove)code; + var pt = Mode == ProgrammingMode.Absolute + ? line.EndPoint + : line.EndPoint + pos; + + if (pt.X > maxX) + maxX = pt.X; + else if (pt.X < minX) + minX = pt.X; + + if (pt.Y > maxY) + maxY = pt.Y; + else if (pt.Y < minY) + minY = pt.Y; + + pos = pt; + + break; + } + + case CodeType.CircularMove: + { + var arc = (CircularMove)code; + var radius = arc.CenterPoint.DistanceTo(arc.EndPoint); + + Vector endpt; + Vector centerpt; + + if (Mode == ProgrammingMode.Incremental) + { + endpt = arc.EndPoint + pos; + centerpt = arc.CenterPoint + pos; + } + else + { + endpt = arc.EndPoint; + centerpt = arc.CenterPoint; + } + + double minX1; + double minY1; + double maxX1; + double maxY1; + + if (pos.X < endpt.X) + { + minX1 = pos.X; + maxX1 = endpt.X; + } + else + { + minX1 = endpt.X; + maxX1 = pos.X; + } + + if (pos.Y < endpt.Y) + { + minY1 = pos.Y; + maxY1 = endpt.Y; + } + else + { + minY1 = endpt.Y; + maxY1 = pos.Y; + } + + var startAngle = pos.AngleFrom(centerpt); + var endAngle = endpt.AngleFrom(centerpt); + + // switch the angle to counter clockwise. + if (arc.Rotation == RotationType.CW) + Generic.Swap(ref startAngle, ref endAngle); + + startAngle = MathHelper.NormalizeAngleRad(startAngle); + endAngle = MathHelper.NormalizeAngleRad(endAngle); + + if (MathHelper.IsAngleBetween(MathHelper.HalfPI, startAngle, endAngle)) + maxY1 = centerpt.Y + radius; + + if (MathHelper.IsAngleBetween(Math.PI, startAngle, endAngle)) + minX1 = centerpt.X - radius; + + const double oneHalfPI = Math.PI * 1.5; + + if (MathHelper.IsAngleBetween(oneHalfPI, startAngle, endAngle)) + minY1 = centerpt.Y - radius; + + if (MathHelper.IsAngleBetween(MathHelper.TwoPI, startAngle, endAngle)) + maxX1 = centerpt.X + radius; + + if (maxX1 > maxX) + maxX = maxX1; + + if (minX1 < minX) + minX = minX1; + + if (maxY1 > maxY) + maxY = maxY1; + + if (minY1 < minY) + minY = minY1; + + pos = endpt; + + break; + } + + case CodeType.SubProgramCall: + { + var subpgm = (SubProgramCall)code; + var box = subpgm.Loop.GetBoundingBox(ref pos); + + if (box.Left < minX) + minX = box.Left; + + if (box.Right > maxX) + maxX = box.Right; + + if (box.Bottom < minY) + minY = box.Bottom; + + if (box.Top > maxY) + maxY = box.Top; + + break; + } + } + } + + return new Box(minX, minY, maxX - minX, maxY - minY); + } + + public static Program Load(Stream stream) + { + var reader = new ProgramReader(); + reader.Read(stream); + return reader.Program; + } + } +} diff --git a/PepLib/ProgrammingMode.cs b/PepLib/ProgrammingMode.cs new file mode 100644 index 0000000..937eb32 --- /dev/null +++ b/PepLib/ProgrammingMode.cs @@ -0,0 +1,8 @@ +namespace PepLib +{ + public enum ProgrammingMode + { + Absolute, + Incremental + } +} diff --git a/PepLib/Properties/AssemblyInfo.cs b/PepLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..02300a8 --- /dev/null +++ b/PepLib/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +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("PepLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PepLib")] +[assembly: AssemblyCopyright("Copyright © AJ Isaacs 2014")] +[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("e62db743-a781-4092-8b6d-bd90f7b25cd1")] + +// 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")] diff --git a/PepLib/Report.Drawing.cs b/PepLib/Report.Drawing.cs new file mode 100644 index 0000000..fb357e1 --- /dev/null +++ b/PepLib/Report.Drawing.cs @@ -0,0 +1,53 @@ +using System; + +namespace PepLib +{ + public partial class Report + { + public class Drawing + { + public string Customer { get; set; } + + public string Name { get; set; } + + public string Revision { get; set; } + + public int QtyRequired { get; set; } + + public int QtyNested { get; set; } + + public int QtyRemaining + { + get { return QtyRequired - QtyNested; } + } + + public double CutDistance { get; set; } + + public double ScribeDistance { get; set; } + + public double BevelDistance { get; set; } + + public TimeSpan TotalCutTime { get; set; } + + public int PierceCount { get; set; } + + public int IntersectionCount { get; set; } + + public double Area1 { get; set; } + + public double Area2 { get; set; } + + public bool IncludeRemnantInCost { get; set; } + + public double NetWeight1 { get; set; } + + public double NetWeight2 { get; set; } + + public double GrossWeight { get; set; } + + public double PercentOfMaterial { get; set; } + + public double PercentOfCutTime { get; set; } + } + } +} diff --git a/PepLib/Report.Plate.cs b/PepLib/Report.Plate.cs new file mode 100644 index 0000000..5a8feca --- /dev/null +++ b/PepLib/Report.Plate.cs @@ -0,0 +1,35 @@ + +namespace PepLib +{ + public partial class Report + { + public class Plate + { + public string Name { get; set; } + + public double Thickness { get; set; } + + public double Width { get; set; } + + public double Length { get; set; } + + public int MaterialNumber { get; set; } + + public string MaterialGrade { get; set; } + + public string MaterialDescription { get; set; } + + public int Quantity { get; set; } + + public double PlateUtilization { get; set; } + + public double MaterialUtilization { get; set; } + + public double Area1 { get; set; } + + public double Area2 { get; set; } + + public int BubblePierceCount { get; set; } + } + } +} diff --git a/PepLib/Report.cs b/PepLib/Report.cs new file mode 100644 index 0000000..358b69a --- /dev/null +++ b/PepLib/Report.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using PepLib.IO; + +namespace PepLib +{ + public partial class Report + { + public Report() + { + Drawings = new List(); + Plates = new List(); + } + + public List Drawings { get; set; } + + public List Plates { get; set; } + + public string Name { get; set; } + + public string Customer { get; set; } + + public DateTime DateProgrammed { get; set; } + + public string Material { get; set; } + + public string ProgrammedBy { get; set; } + + public string Machine { get; set; } + + public string Comments { get; set; } + + public string Remarks { get; set; } + + public TimeSpan TotalCutTime { get; set; } + + public double TotalGasUsed { get; set; } + + public double TotalRapidDistance { get; set; } + + public int TotalHeadRaises { get; set; } + + public double CutFeedrate { get; set; } + + public double RapidFeedrate { get; set; } + + public TimeSpan PierceTime { get; set; } + + public int PlateCount() + { + return Plates.Sum(plate => plate.Quantity); + } + + public int ProgramCount() + { + return Plates.Count; + } + + public double CutDistance() + { + return Drawings.Sum(dwg => dwg.CutDistance); + } + + public double ScribeDistance() + { + return Drawings.Sum(dwg => dwg.ScribeDistance); + } + + public double BevelDistance() + { + return Drawings.Sum(dwg => dwg.BevelDistance); + } + + public int TotalPierceCount() + { + return Drawings.Sum(dwg => dwg.PierceCount); + } + + public static Report Load(string nestFile) + { + var reader = new ReportReader(); + reader.Read(nestFile); + return reader.Report; + } + + public static Report Load(Stream stream) + { + var reader = new ReportReader(); + reader.Read(stream); + return reader.Report; + } + + public static bool TryLoad(string nestfile, out Report report) + { + try + { + report = Load(nestfile); + } + catch (Exception) + { + report = null; + return false; + } + + return true; + } + + public static bool TryLoad(Stream stream, out Report report) + { + try + { + report = Load(stream); + } + catch (Exception) + { + report = null; + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/PepLib/RotationType.cs b/PepLib/RotationType.cs new file mode 100644 index 0000000..bb33c51 --- /dev/null +++ b/PepLib/RotationType.cs @@ -0,0 +1,16 @@ + +namespace PepLib +{ + public enum RotationType + { + /// + /// Clockwise + /// + CW, + + /// + /// Counter-Clockwise + /// + CCW + } +} diff --git a/PepLib/Size.cs b/PepLib/Size.cs new file mode 100644 index 0000000..fd9f2cb --- /dev/null +++ b/PepLib/Size.cs @@ -0,0 +1,45 @@ +namespace PepLib +{ + public class Size + { + public Size(double height, double width) + { + Height = height; + Width = width; + } + + public double Height { get; set; } + + public double Width { get; set; } + + public static Size Parse(string size) + { + var a = size.ToUpper().Split('X'); + + var height = double.Parse(a[0]); + var width = double.Parse(a[1]); + + return new Size(height, width); + } + + public static bool TryParse(string s, out Size size) + { + try + { + size = Parse(s); + } + catch + { + size = new Size(0, 0); + return false; + } + + return true; + } + + public override string ToString() + { + return string.Format("{0} x {1}", Height, Width); + } + } +} \ No newline at end of file diff --git a/PepLib/Spacing.cs b/PepLib/Spacing.cs new file mode 100644 index 0000000..3fdfc81 --- /dev/null +++ b/PepLib/Spacing.cs @@ -0,0 +1,27 @@ + +namespace PepLib +{ + public class Spacing + { + public Spacing() + : this(0, 0, 0, 0) + { + } + + public Spacing(double l, double b, double r, double t) + { + Left = l; + Bottom = b; + Right = r; + Top = t; + } + + public double Left { get; set; } + + public double Bottom { get; set; } + + public double Right { get; set; } + + public double Top { get; set; } + } +} diff --git a/PepLib/StatusType.cs b/PepLib/StatusType.cs new file mode 100644 index 0000000..d08bdb3 --- /dev/null +++ b/PepLib/StatusType.cs @@ -0,0 +1,11 @@ + +namespace PepLib +{ + public enum StatusType + { + ToBeCut, + Quote, + HasBeenCut, + Temp + } +} diff --git a/PepLib/Tolerance.cs b/PepLib/Tolerance.cs new file mode 100644 index 0000000..74cc01b --- /dev/null +++ b/PepLib/Tolerance.cs @@ -0,0 +1,14 @@ +using System; + +namespace PepLib +{ + public static class Tolerance + { + public const double Epsilon = 0.0001; + + public static bool IsEqualTo(this double a, double b, double tolerance = Epsilon) + { + return Math.Abs(b - a) <= tolerance; + } + } +} diff --git a/PepLib/Util.cs b/PepLib/Util.cs new file mode 100644 index 0000000..49ed57f --- /dev/null +++ b/PepLib/Util.cs @@ -0,0 +1,32 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace PepLib +{ + public static class Util + { + public static string GetNestFileFormat(string filename) + { + try + { + var name = Path.GetFileName(filename); + var ext = Path.GetExtension(name); + + if (name.LastIndexOf(ext) > 5 && !name.Contains("-")) + name = name.Insert(5, "-"); + + if (name.LastIndexOf(ext) > 8 && char.IsLetter(name[8])) + name = name.Remove(8, 1); + + return Path.Combine(Path.GetDirectoryName(filename), name); + } + catch (SystemException ex) + { + Debug.WriteLine(ex.Message); + } + + return string.Empty; + } + } +} diff --git a/PepLib/Vector.cs b/PepLib/Vector.cs new file mode 100644 index 0000000..dda5cc2 --- /dev/null +++ b/PepLib/Vector.cs @@ -0,0 +1,124 @@ +using System; + +namespace PepLib +{ + public struct Vector + { + public double X; + public double Y; + + public Vector(double x, double y) + { + X = x; + Y = y; + } + + public double DistanceTo(Vector pt) + { + double vx = pt.X - this.X; + double vy = pt.Y - this.Y; + + return Math.Sqrt(vx * vx + vy * vy); + } + + public double DistanceTo(double x, double y) + { + double vx = x - this.X; + double vy = y - this.Y; + + return Math.Sqrt(vx * vx + vy * vy); + } + + public double Angle() + { + return MathHelper.NormalizeAngleRad(Math.Atan2(Y, X)); + } + + public double AngleTo(Vector pt) + { + return (pt - this).Angle(); + } + + public double AngleFrom(Vector pt) + { + return (this - pt).Angle(); + } + + public static Vector operator +(Vector pt1, Vector pt2) + { + return new Vector(pt1.X + pt2.X, pt1.Y + pt2.Y); + } + + public static Vector operator -(Vector pt1, Vector pt2) + { + return new Vector(pt1.X - pt2.X, pt1.Y - pt2.Y); + } + + public static Vector operator -(Vector pt) + { + return new Vector(-pt.X, -pt.Y); + } + + public static bool operator ==(Vector pt1, Vector pt2) + { + return pt1.DistanceTo(pt2) <= Tolerance.Epsilon; + } + + public static bool operator !=(Vector pt1, Vector pt2) + { + return !(pt1 == pt2); + } + + public Vector Rotate(double angle) + { + var v = new Vector(); + + double cos = Math.Cos(angle); + double sin = Math.Sin(angle); + + v.X = X * cos - Y * sin; + v.Y = X * sin + Y * cos; + + return v; + } + + public Vector Rotate(double angle, Vector origin) + { + var v = new Vector(); + var pt = this - origin; + + double cos = Math.Cos(angle); + double sin = Math.Sin(angle); + + v.X = pt.X * cos - pt.Y * sin + origin.X; + v.Y = pt.X * sin + pt.Y * cos + origin.Y; + + return v; + } + + public Vector Clone() + { + return new Vector(X, Y); + } + + public override bool Equals(object obj) + { + if (!(obj is Vector)) + return false; + + var pt = (Vector)obj; + + return (X.IsEqualTo(pt.X)) && (Y.IsEqualTo(pt.Y)); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override string ToString() + { + return string.Format("[Vector: X:{0}, Y:{1}]", X, Y); + } + } +} diff --git a/PepLib/ZipHelper.cs b/PepLib/ZipHelper.cs new file mode 100644 index 0000000..fba1140 --- /dev/null +++ b/PepLib/ZipHelper.cs @@ -0,0 +1,116 @@ +using Ionic.Zip; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; + +namespace PepLib +{ + public static class ZipHelper + { + /// + /// Returns the files that match the specified pattern. + /// + /// Input zip file. + /// Pattern to match. + /// Names of the files that match the pattern. + /// Data of the files that match the pattern. + /// + public static int ExtractByPattern(string file, string pattern, out string[] names, out Stream[] streams) + { + var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read); + var zipStream = new ZipInputStream(fileStream); + var nameList = new List(); + var streamList = new List(); + + ZipEntry theEntry; + + while ((theEntry = zipStream.GetNextEntry()) != null) + { + if (!Regex.IsMatch(theEntry.FileName, pattern)) + continue; + + nameList.Add(theEntry.FileName); + + var memstream = new MemoryStream(); + var size = 2048; + var data = new byte[size]; + + while (true) + { + size = zipStream.Read(data, 0, data.Length); + + if (size > 0) + { + memstream.Write(data, 0, size); + memstream.Flush(); + } + else break; + } + + memstream.Seek(0, SeekOrigin.Begin); + streamList.Add(memstream); + } + + zipStream.Close(); + + names = nameList.ToArray(); + streams = streamList.ToArray(); + + return streams.Length; + } + + /// + /// Returns the first file found that matches the specified file extension. + /// + /// Input zip file. + /// Extension to match. + /// The name of the file that matches the file extension. + /// The data of the file that matches the file extension. + /// + public static bool ExtractByExtension(string file, string extension, out string name, out Stream stream) + { + var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read); + var zipStream = new ZipInputStream(fileStream); + var memstream = new MemoryStream(); + + ZipEntry theEntry; + + while ((theEntry = zipStream.GetNextEntry()) != null) + { + if (Path.GetExtension(theEntry.FileName) != extension) + continue; + + int size = 2048; + var data = new byte[size]; + + while (true) + { + size = zipStream.Read(data, 0, data.Length); + + if (size > 0) + { + memstream.Write(data, 0, size); + memstream.Flush(); + } + else break; + } + + zipStream.Close(); + memstream.Seek(0, SeekOrigin.Begin); + + stream = memstream; + name = theEntry.FileName; + + return true; + } + + zipStream.Close(); + memstream.Close(); + + stream = null; + name = null; + + return false; + } + } +} diff --git a/PepLib/packages.config b/PepLib/packages.config new file mode 100644 index 0000000..910ba14 --- /dev/null +++ b/PepLib/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file