Compare commits

...

5 Commits

Author SHA1 Message Date
aj 955fbc5539 fix(nests): use partial matching for customer filter in SearchParts
The customer parameter on the parts search endpoint was doing exact
equality matching against CustomerName/CustID, so partial values like
"sull" would never match "Sullys". Changed to case-insensitive
Contains matching, consistent with how the search term is handled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 12:41:35 -05:00
aj 72cdb32750 refactor(PepLib.Core): modernize and deduplicate Program class
- Extract ApplyTransform() to consolidate Rotate/Offset methods
- Add BoundsTracker helper class for bounding box calculations
- Extract ProcessLinearMotion/ProcessCircularMotion helpers
- Use pattern matching instead of type checks and casts
- Use foreach loops instead of indexed for loops
- Use expression-bodied members for simple methods
- Use tuple deconstruction and Math.Min/Max

Reduces code from 368 to 227 lines (~38% reduction).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 09:53:20 -05:00
aj a0c707583d refactor(PepLib.Core): move Node classes to Utilities namespace
Node and KeyNode are INI parsing helpers used by IniConfig,
not geometry types. Move from Geometry/ to Utilities/.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 09:32:43 -05:00
aj 9088af52de refactor(PepLib.Core): reorganize files into logical folder structure
Move 38 files from root directory into organized subfolders:
- Enums/ (7 files): StatusType, ApplicationType, DrawingType, etc.
- Geometry/ (5 files): Vector, Box, Size, Spacing, Node
- Models/ (15 files): Nest, Plate, Part, Program, Report, etc.
- Utilities/ (7 files): MathHelper, Tolerance, ZipHelper, etc.
- Extensions/ (2 files): PartListExtensions, PlateListExtensions
- Interfaces/ (1 file): IMovable

Update namespaces to follow folder hierarchy (e.g., PepLib.Models).
Add GlobalUsings.cs for internal backward compatibility.
Update Codes/ and IO/ files with new using statements.
Update PepApi.Core consumers to reference new namespaces.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 09:29:13 -05:00
aj c5be48a807 feat(drawings): add drawings API endpoint with comprehensive filtering
Add new /drawings endpoint with support for filtering by text fields,
date ranges, dimensions, and boolean flags. Includes MCP tools for
integration with Claude Code.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 13:11:42 -05:00
62 changed files with 1179 additions and 439 deletions
@@ -0,0 +1,228 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PepApi.Core.Models;
using PepLib.Data;
namespace PepApi.Core.Controllers;
[ApiController]
[Route("drawings")]
public class DrawingsController : ControllerBase
{
private readonly PepDB _db;
public DrawingsController(PepDB db)
{
_db = db;
}
/// <summary>
/// Get a list of drawings with optional filtering.
/// </summary>
[HttpGet]
public async Task<ActionResult<List<DrawingSummary>>> GetDrawings([FromQuery] DrawingFilterData? filter)
{
var drawings = await _db.Drawings
.Select(d => new DrawingSummary
{
ID = d.ID,
Name = d.Name,
Customer = d.Customer,
CustID = d.CustID,
Revision = d.Revision,
Description = d.Description,
Material = d.Material,
MaterialGrade = d.MatGrade,
Status = d.Status,
Type = d.Type,
Application = d.Application,
Programmer = d.Programmer,
CreatedBy = d.CreatedBy,
Width = d.Width,
Length = d.Length,
TrueArea = d.TrueArea,
CutLength = d.CutLength,
CreationDate = d.CreationDate,
LastEditDate = d.LastEditDate,
ModifiedDate = d.ModifiedDate,
HasBevel = d.HasBevel != 0,
HasLeadIn = d.HasLeadIn != 0,
HasTab = d.HasTab != 0
})
.ToListAsync();
if (filter != null)
{
var filtered = filter.Apply(drawings.AsQueryable()).ToList();
var paginated = filtered.Skip(filter.Offset).Take(filter.Limit).ToList();
return Ok(paginated);
}
return Ok(drawings.Take(100).ToList());
}
/// <summary>
/// Get a drawing by ID.
/// </summary>
[HttpGet("{id:int}")]
public async Task<ActionResult<DrawingDetails>> GetDrawingById(int id)
{
var drawing = await _db.Drawings
.Where(d => d.ID == id)
.FirstOrDefaultAsync();
if (drawing == null)
return NotFound(new { message = "Drawing not found" });
return Ok(ConvertToDetails(drawing));
}
/// <summary>
/// Get a drawing by exact name.
/// </summary>
[HttpGet("name/{name}")]
public async Task<ActionResult<DrawingDetails>> GetDrawingByName(string name)
{
var drawing = await _db.Drawings
.Where(d => d.Name.ToUpper() == name.ToUpper())
.FirstOrDefaultAsync();
if (drawing == null)
return NotFound(new { message = "Drawing not found" });
return Ok(ConvertToDetails(drawing));
}
/// <summary>
/// Search drawings by partial name.
/// </summary>
[HttpGet("search")]
public async Task<ActionResult<DrawingSearchResponse>> SearchDrawings(
[FromQuery] string search,
[FromQuery] int limit = 100)
{
if (string.IsNullOrWhiteSpace(search))
return BadRequest(new { message = "Search term is required" });
var searchUpper = search.Trim().ToUpper();
var allMatches = await _db.Drawings
.Where(d => d.Name.ToUpper().Contains(searchUpper))
.Select(d => new DrawingSummary
{
ID = d.ID,
Name = d.Name,
Customer = d.Customer,
CustID = d.CustID,
Revision = d.Revision,
Description = d.Description,
Material = d.Material,
MaterialGrade = d.MatGrade,
Status = d.Status,
Type = d.Type,
Application = d.Application,
Programmer = d.Programmer,
CreatedBy = d.CreatedBy,
Width = d.Width,
Length = d.Length,
TrueArea = d.TrueArea,
CutLength = d.CutLength,
CreationDate = d.CreationDate,
LastEditDate = d.LastEditDate,
ModifiedDate = d.ModifiedDate,
HasBevel = d.HasBevel != 0,
HasLeadIn = d.HasLeadIn != 0,
HasTab = d.HasTab != 0
})
.ToListAsync();
var limitedResults = limit > 0 ? allMatches.Take(limit).ToList() : allMatches;
return Ok(new DrawingSearchResponse
{
SearchTerm = search,
TotalMatches = allMatches.Count,
ResultsReturned = limitedResults.Count,
Results = limitedResults
});
}
private static DrawingDetails ConvertToDetails(Drawing drawing)
{
return new DrawingDetails
{
ID = drawing.ID,
Name = drawing.Name,
CustID = drawing.CustID,
Revision = drawing.Revision,
Path = drawing.Path,
File = drawing.File,
InUseBy = drawing.InUseBy,
InUseDate = drawing.InUseDate,
Status = drawing.Status,
StatusModifiedBy = drawing.StatusModifiedBy,
StatusModifiedDate = drawing.StatusModifiedDate,
CreationDate = drawing.CreationDate,
LastEditDate = drawing.LastEditDate,
LastRefDate = drawing.LastRefDate,
Description = drawing.Description,
Customer = drawing.Customer,
Comment = drawing.Comment,
Notes = drawing.Notes,
Grain = drawing.Grain,
GrainAngle = drawing.GrainAngle,
Material = drawing.Material,
MaterialGrade = drawing.MatGrade,
Programmer = drawing.Programmer,
CreatedBy = drawing.CreatedBy,
Type = drawing.Type,
CommonCut = drawing.CommonCut,
CombineCut = drawing.CombineCut,
Errors = drawing.Errors,
Hardness = drawing.Hardness,
Specification = drawing.Specification,
NestInCutOuts = drawing.NestInCutOuts,
UserDefined1 = drawing.UserDefined1,
UserDefined2 = drawing.UserDefined2,
UserDefined3 = drawing.UserDefined3,
UserDefined4 = drawing.UserDefined4,
UserDefined5 = drawing.UserDefined5,
UserDefined6 = drawing.UserDefined6,
Machine = drawing.Machine,
Application = drawing.Application,
PartCount = drawing.PartCount,
Color = drawing.Color,
CombineMethod = drawing.CombineMethod,
SeqCutouts = drawing.SeqCutouts,
AllowMirror = drawing.AllowMirror,
SourceFile = drawing.SourceFile,
SourceDate = drawing.SourceDate,
SourceSize = drawing.SourceSize,
CadScaled = drawing.CadScaled,
CadDimVerified = drawing.CadDimVerified,
CadDimCount = drawing.CadDimCount,
Width = drawing.Width,
Length = drawing.Length,
RectArea = drawing.RectArea,
ExtArea = drawing.ExtArea,
TrueArea = drawing.TrueArea,
ExtUtil = drawing.ExtUtil,
TrueUtil = drawing.TrueUtil,
SmallestAreaAng = drawing.SmallestAreaAng,
SmallestAreaLen = drawing.SmallestAreaLen,
SmallestAreaWid = drawing.SmallestAreaWid,
SmallestYAng = drawing.SmallestYAng,
SmallestYLen = drawing.SmallestYLen,
SmallestYWid = drawing.SmallestYWid,
CutLength = drawing.CutLength,
ScribeLength = drawing.ScribeLength,
Checked = drawing.Checked,
PepBendStatus = drawing.PepBendStatus,
HasBevel = drawing.HasBevel != 0,
HasLeadIn = drawing.HasLeadIn != 0,
HasTab = drawing.HasTab != 0,
ModifiedDate = drawing.ModifiedDate,
ModifiedBy = drawing.ModifiedBy
};
}
}
+7 -2
View File
@@ -3,8 +3,8 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using PepApi.Core.Configuration;
using PepApi.Core.Models;
using PepLib;
using PepLib.Data;
using PepLib.Models;
using Plate = PepApi.Core.Models.Plate;
namespace PepApi.Core.Controllers;
@@ -216,7 +216,12 @@ public class NestsController : ControllerBase
nestsQuery = nestsQuery.Where(n => n.DateProgrammed!.Value.Year == year.Value);
if (!string.IsNullOrWhiteSpace(customer))
nestsQuery = nestsQuery.Where(n => n.CustomerName == customer || n.CustID == customer);
{
var customerUpper = customer.Trim().ToUpper();
nestsQuery = nestsQuery.Where(n =>
(n.CustomerName != null && n.CustomerName.ToUpper().Contains(customerUpper)) ||
(n.CustID != null && n.CustID.ToUpper().Contains(customerUpper)));
}
var nests = await nestsQuery
.Select(n => new
+1 -1
View File
@@ -1,5 +1,5 @@
using PepApi.Core.Models;
using PepLib;
using PepLib.Models;
namespace PepApi.Core
{
+149
View File
@@ -0,0 +1,149 @@
namespace PepApi.Core.Models
{
public class DrawingDetails
{
public int ID { get; set; }
public required string Name { get; set; }
public required string CustID { get; set; }
public required string Revision { get; set; }
public required string Path { get; set; }
public required string File { get; set; }
public required string InUseBy { get; set; }
public DateTime? InUseDate { get; set; }
public required string Status { get; set; }
public required string StatusModifiedBy { get; set; }
public DateTime? StatusModifiedDate { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? LastEditDate { get; set; }
public DateTime? LastRefDate { get; set; }
public required string Description { get; set; }
public required string Customer { get; set; }
public required string Comment { get; set; }
public required string Notes { get; set; }
public byte Grain { get; set; }
public double GrainAngle { get; set; }
public required string Material { get; set; }
public required string MaterialGrade { get; set; }
public required string Programmer { get; set; }
public required string CreatedBy { get; set; }
public required string Type { get; set; }
public byte CommonCut { get; set; }
public byte CombineCut { get; set; }
public required string Errors { get; set; }
public required string Hardness { get; set; }
public required string Specification { get; set; }
public byte NestInCutOuts { get; set; }
public required string UserDefined1 { get; set; }
public required string UserDefined2 { get; set; }
public required string UserDefined3 { get; set; }
public required string UserDefined4 { get; set; }
public required string UserDefined5 { get; set; }
public required string UserDefined6 { get; set; }
public short Machine { get; set; }
public required string Application { get; set; }
public int PartCount { get; set; }
public int Color { get; set; }
public short CombineMethod { get; set; }
public byte SeqCutouts { get; set; }
public byte AllowMirror { get; set; }
public required string SourceFile { get; set; }
public DateTime? SourceDate { get; set; }
public int SourceSize { get; set; }
public required string CadScaled { get; set; }
public int CadDimVerified { get; set; }
public int CadDimCount { get; set; }
public double Width { get; set; }
public double Length { get; set; }
public double RectArea { get; set; }
public double ExtArea { get; set; }
public double TrueArea { get; set; }
public double ExtUtil { get; set; }
public double TrueUtil { get; set; }
public double SmallestAreaAng { get; set; }
public double SmallestAreaLen { get; set; }
public double SmallestAreaWid { get; set; }
public double SmallestYAng { get; set; }
public double SmallestYLen { get; set; }
public double SmallestYWid { get; set; }
public double CutLength { get; set; }
public double ScribeLength { get; set; }
public int Checked { get; set; }
public byte PepBendStatus { get; set; }
public bool HasBevel { get; set; }
public bool HasLeadIn { get; set; }
public bool HasTab { get; set; }
public DateTime? ModifiedDate { get; set; }
public required string ModifiedBy { get; set; }
}
}
+210
View File
@@ -0,0 +1,210 @@
namespace PepApi.Core.Models
{
public class DrawingFilterData
{
// Text filters (partial, case-insensitive)
public string? Name { get; set; }
public string? Customer { get; set; }
public string? CustID { get; set; }
public string? Description { get; set; }
public string? Revision { get; set; }
public string? Material { get; set; }
public string? MaterialGrade { get; set; }
public string? Hardness { get; set; }
public string? Specification { get; set; }
public string? Programmer { get; set; }
public string? CreatedBy { get; set; }
public string? ModifiedBy { get; set; }
// Exact match filters
public string? Status { get; set; }
public string? Type { get; set; }
public string? Application { get; set; }
// Date range filters
public DateTime? CreatedAfter { get; set; }
public DateTime? CreatedBefore { get; set; }
public DateTime? ModifiedAfter { get; set; }
public DateTime? ModifiedBefore { get; set; }
public DateTime? LastEditAfter { get; set; }
public DateTime? LastEditBefore { get; set; }
// Dimension range filters
public double? MinWidth { get; set; }
public double? MaxWidth { get; set; }
public double? MinLength { get; set; }
public double? MaxLength { get; set; }
public double? MinArea { get; set; }
public double? MaxArea { get; set; }
// Boolean filters
public bool? HasBevel { get; set; }
public bool? HasLeadIn { get; set; }
public bool? HasTab { get; set; }
// Pagination
public int Offset { get; set; } = 0;
public int Limit { get; set; } = 100;
public IQueryable<DrawingSummary> Apply(IQueryable<DrawingSummary> drawings)
{
// Text filters (partial, case-insensitive)
if (this.Name != null)
{
var x = this.Name.ToUpper();
drawings = drawings.Where(d => d.Name.ToUpper().Contains(x));
}
if (this.Customer != null)
{
var x = this.Customer.ToUpper();
drawings = drawings.Where(d => d.Customer.ToUpper().Contains(x));
}
if (this.CustID != null)
{
var x = this.CustID.ToUpper();
drawings = drawings.Where(d => d.CustID.ToUpper().Contains(x));
}
if (this.Description != null)
{
var x = this.Description.ToUpper();
drawings = drawings.Where(d => d.Description.ToUpper().Contains(x));
}
if (this.Revision != null)
{
var x = this.Revision.ToUpper();
drawings = drawings.Where(d => d.Revision.ToUpper().Contains(x));
}
if (this.Material != null)
{
var x = this.Material.ToUpper();
drawings = drawings.Where(d => d.Material.ToUpper().Contains(x));
}
if (this.MaterialGrade != null)
{
var x = this.MaterialGrade.ToUpper();
drawings = drawings.Where(d => d.MaterialGrade.ToUpper().Contains(x));
}
if (this.Programmer != null)
{
var x = this.Programmer.ToUpper();
drawings = drawings.Where(d => d.Programmer.ToUpper().Contains(x));
}
if (this.CreatedBy != null)
{
var x = this.CreatedBy.ToUpper();
drawings = drawings.Where(d => d.CreatedBy.ToUpper().Contains(x));
}
// Exact match filters
if (this.Status != null)
{
var x = this.Status.ToUpper();
drawings = drawings.Where(d => d.Status.ToUpper() == x);
}
if (this.Type != null)
{
var x = this.Type.ToUpper();
drawings = drawings.Where(d => d.Type.ToUpper() == x);
}
if (this.Application != null)
{
var x = this.Application.ToUpper();
drawings = drawings.Where(d => d.Application.ToUpper() == x);
}
// Date range filters - CreationDate
if (this.CreatedAfter != null)
{
drawings = drawings.Where(d => d.CreationDate >= this.CreatedAfter);
}
if (this.CreatedBefore != null)
{
drawings = drawings.Where(d => d.CreationDate <= this.CreatedBefore);
}
// Date range filters - ModifiedDate
if (this.ModifiedAfter != null)
{
drawings = drawings.Where(d => d.ModifiedDate >= this.ModifiedAfter);
}
if (this.ModifiedBefore != null)
{
drawings = drawings.Where(d => d.ModifiedDate <= this.ModifiedBefore);
}
// Date range filters - LastEditDate
if (this.LastEditAfter != null)
{
drawings = drawings.Where(d => d.LastEditDate >= this.LastEditAfter);
}
if (this.LastEditBefore != null)
{
drawings = drawings.Where(d => d.LastEditDate <= this.LastEditBefore);
}
// Dimension range filters - Width
if (this.MinWidth != null)
{
drawings = drawings.Where(d => d.Width >= this.MinWidth);
}
if (this.MaxWidth != null)
{
drawings = drawings.Where(d => d.Width <= this.MaxWidth);
}
// Dimension range filters - Length
if (this.MinLength != null)
{
drawings = drawings.Where(d => d.Length >= this.MinLength);
}
if (this.MaxLength != null)
{
drawings = drawings.Where(d => d.Length <= this.MaxLength);
}
// Dimension range filters - Area (TrueArea)
if (this.MinArea != null)
{
drawings = drawings.Where(d => d.TrueArea >= this.MinArea);
}
if (this.MaxArea != null)
{
drawings = drawings.Where(d => d.TrueArea <= this.MaxArea);
}
// Boolean filters
if (this.HasBevel != null)
{
drawings = drawings.Where(d => d.HasBevel == this.HasBevel);
}
if (this.HasLeadIn != null)
{
drawings = drawings.Where(d => d.HasLeadIn == this.HasLeadIn);
}
if (this.HasTab != null)
{
drawings = drawings.Where(d => d.HasTab == this.HasTab);
}
return drawings;
}
}
}
@@ -0,0 +1,9 @@
namespace PepApi.Core.Models;
public class DrawingSearchResponse
{
public required string SearchTerm { get; set; }
public int TotalMatches { get; set; }
public int ResultsReturned { get; set; }
public List<DrawingSummary> Results { get; set; } = [];
}
+51
View File
@@ -0,0 +1,51 @@
namespace PepApi.Core.Models
{
public class DrawingSummary
{
public int ID { get; set; }
public required string Name { get; set; }
public required string Customer { get; set; }
public required string CustID { get; set; }
public required string Revision { get; set; }
public required string Description { get; set; }
public required string Material { get; set; }
public required string MaterialGrade { get; set; }
public required string Status { get; set; }
public required string Type { get; set; }
public required string Application { get; set; }
public required string Programmer { get; set; }
public required string CreatedBy { get; set; }
public double Width { get; set; }
public double Length { get; set; }
public double TrueArea { get; set; }
public double CutLength { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? LastEditDate { get; set; }
public DateTime? ModifiedDate { get; set; }
public bool HasBevel { get; set; }
public bool HasLeadIn { get; set; }
public bool HasTab { get; set; }
}
}
+6 -6
View File
@@ -1,4 +1,4 @@
using PepLib;
using PepLib.Models;
using Material = PepApi.Core.Models.Material;
using Part = PepApi.Core.Models.Part;
using Plate = PepApi.Core.Models.Plate;
@@ -8,7 +8,7 @@ namespace PepApi.Core
{
internal static class PepHelper
{
public static bool IsTestSquare(PepLib.Part part)
public static bool IsTestSquare(PepLib.Models.Part part)
{
if (part == null || part.DrawingName == null)
return false;
@@ -39,7 +39,7 @@ namespace PepApi.Core
return count;
}
public static bool AreTestSquaresInCorrectOrder(PepLib.Plate plate)
public static bool AreTestSquaresInCorrectOrder(PepLib.Models.Plate plate)
{
var partsStarted = false;
@@ -68,7 +68,7 @@ namespace PepApi.Core
return true;
}
public static bool AreTestSquaresInCorrectOrder(PepLib.Nest nest)
public static bool AreTestSquaresInCorrectOrder(PepLib.Models.Nest nest)
{
foreach (var plate in nest.Plates)
{
@@ -229,7 +229,7 @@ namespace PepApi.Core
.ToList();
}
public static Material GetMaterial(PepLib.Plate plate)
public static Material GetMaterial(PepLib.Models.Plate plate)
{
return new Material
{
@@ -240,7 +240,7 @@ namespace PepApi.Core
};
}
public static Material GetMaterial(PepLib.Nest nest)
public static Material GetMaterial(PepLib.Models.Nest nest)
{
return GetMaterial(nest.Plates.First());
}
+3 -1
View File
@@ -1,4 +1,6 @@
using PepLib.Enums;
using PepLib.Geometry;
namespace PepLib.Codes
{
public class CircularMove : Motion
+2 -1
View File
@@ -1,4 +1,5 @@
using PepLib.Geometry;
namespace PepLib.Codes
{
public class LinearMove : Motion
+3 -1
View File
@@ -1,4 +1,6 @@
using PepLib.Geometry;
using PepLib.Interfaces;
namespace PepLib.Codes
{
public abstract class Motion : IMovable, ICode
+3 -1
View File
@@ -1,4 +1,6 @@
namespace PepLib.Codes
using PepLib.Geometry;
namespace PepLib.Codes
{
public class RapidMove : Motion
{
+2 -1
View File
@@ -1,4 +1,5 @@
using PepLib.Enums;
namespace PepLib.Codes
{
public class SetKerf : ICode
+3 -1
View File
@@ -1,4 +1,6 @@
using PepLib.Models;
using PepLib.Utilities;
namespace PepLib.Codes
{
public class SubProgramCall : ICode
@@ -1,5 +1,5 @@

namespace PepLib
namespace PepLib.Enums
{
public enum ApplicationType
{
@@ -1,5 +1,5 @@

namespace PepLib
namespace PepLib.Enums
{
public enum DrawingType
{
@@ -1,5 +1,5 @@

namespace PepLib
namespace PepLib.Enums
{
public enum GrainType
{
@@ -1,5 +1,5 @@

namespace PepLib
namespace PepLib.Enums
{
public enum KerfType
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Enums
{
public enum ProgrammingMode
{
@@ -1,5 +1,5 @@

namespace PepLib
namespace PepLib.Enums
{
public enum RotationType
{
@@ -1,5 +1,5 @@

namespace PepLib
namespace PepLib.Enums
{
public enum StatusType
{
@@ -1,4 +1,7 @@
namespace PepLib
using PepLib.Geometry;
using PepLib.Models;
namespace PepLib.Extensions
{
public static class PartListExtensions
{
@@ -1,4 +1,6 @@
namespace PepLib
using PepLib.Models;
namespace PepLib.Extensions
{
public static class PlateListExtensions
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Geometry
{
public class Box
{
@@ -10,7 +10,7 @@
public Box(double x, double y, double w, double h)
{
Location = new Vector(x, y);
Size = new PepLib.Size(0, 0);
Size = new Size(0, 0);
Width = w;
Height = h;
}
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Geometry
{
public class Size
{
@@ -42,4 +42,4 @@
return string.Format("{0} x {1}", Height, Width);
}
}
}
}
@@ -1,5 +1,5 @@

namespace PepLib
namespace PepLib.Geometry
{
public class Spacing
{
@@ -1,4 +1,6 @@
namespace PepLib
using PepLib.Utilities;
namespace PepLib.Geometry
{
public struct Vector
{
+6
View File
@@ -0,0 +1,6 @@
global using PepLib.Enums;
global using PepLib.Geometry;
global using PepLib.Models;
global using PepLib.Utilities;
global using PepLib.Extensions;
global using PepLib.Interfaces;
+4 -1
View File
@@ -1,4 +1,7 @@
using System.Text;
using PepLib.Enums;
using PepLib.Models;
using PepLib.Utilities;
using System.Text;
namespace PepLib.IO
{
+1
View File
@@ -1,3 +1,4 @@
using PepLib.Models;
using System.Diagnostics;
using System.IO.Compression;
using System.Text.RegularExpressions;
+2
View File
@@ -1,4 +1,6 @@
using PepLib.Codes;
using PepLib.Geometry;
using PepLib.Models;
namespace PepLib.IO
{
+4 -1
View File
@@ -1,4 +1,7 @@
using System.Text;
using PepLib.Enums;
using PepLib.Models;
using PepLib.Utilities;
using System.Text;
namespace PepLib.IO
{
+1
View File
@@ -1,3 +1,4 @@
using PepLib.Models;
using System.Diagnostics;
using System.IO.Compression;
using System.Text;
+3
View File
@@ -1,4 +1,7 @@
using PepLib.Codes;
using PepLib.Geometry;
using PepLib.Models;
using PepLib.Utilities;
namespace PepLib.IO
{
+3
View File
@@ -1,4 +1,7 @@
using PepLib.Codes;
using PepLib.Enums;
using PepLib.Geometry;
using PepLib.Models;
using System.Text;
namespace PepLib.IO
+3 -1
View File
@@ -1,4 +1,6 @@
using System.Diagnostics;
using PepLib.Models;
using PepLib.Utilities;
using System.Diagnostics;
namespace PepLib.IO
{
@@ -1,4 +1,6 @@
namespace PepLib
using PepLib.Geometry;
namespace PepLib.Interfaces
{
public interface IMovable
{
@@ -1,7 +1,8 @@
using PepLib.Codes;
using PepLib.Codes;
using PepLib.Enums;
using PepLib.IO;
namespace PepLib
namespace PepLib.Models
{
public class Drawing
{
@@ -1,6 +1,7 @@
using PepLib.Enums;
using PepLib.IO;
namespace PepLib
namespace PepLib.Models
{
public class DrawingInfo
{
@@ -103,4 +104,3 @@ namespace PepLib
}
}
}
@@ -1,6 +1,8 @@
using PepLib.Codes;
using PepLib.Codes;
using PepLib.Enums;
using PepLib.Geometry;
namespace PepLib
namespace PepLib.Models
{
public class Loop : Program
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Models
{
public class Machine
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Models
{
public class Material
{
@@ -1,7 +1,7 @@
using PepLib.Codes;
using PepLib.Codes;
using PepLib.IO;
namespace PepLib
namespace PepLib.Models
{
public class Nest
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Models
{
public class NestDrawing
{
@@ -1,7 +1,7 @@
using PepLib.IO;
using PepLib.IO;
using System.Text;
namespace PepLib
namespace PepLib.Models
{
public class NestIndex
{
@@ -1,6 +1,7 @@
using PepLib.IO;
using PepLib.Enums;
using PepLib.IO;
namespace PepLib
namespace PepLib.Models
{
public class NestInfo
{
@@ -94,4 +95,4 @@ namespace PepLib
return true;
}
}
}
}
@@ -1,4 +1,8 @@
namespace PepLib
using PepLib.Enums;
using PepLib.Geometry;
using PepLib.Interfaces;
namespace PepLib.Models
{
public class Part : IMovable
{
@@ -1,4 +1,9 @@
namespace PepLib
using PepLib.Extensions;
using PepLib.Geometry;
using PepLib.Interfaces;
using PepLib.Utilities;
namespace PepLib.Models
{
public class Plate : IMovable
{
+226
View File
@@ -0,0 +1,226 @@
using PepLib.Codes;
using PepLib.Enums;
using PepLib.Geometry;
using PepLib.Interfaces;
using PepLib.IO;
using PepLib.Utilities;
namespace PepLib.Models
{
public class Program : List<ICode>, IMovable
{
private ProgrammingMode mode;
public Program(ProgrammingMode mode = ProgrammingMode.Absolute)
{
Mode = mode;
}
public ProgrammingMode Mode
{
get => 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);
foreach (var code in this)
{
if (code is Motion motion)
{
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);
foreach (var code in this)
{
if (code is Motion motion)
{
motion.Offset(pos);
pos = motion.EndPoint;
}
}
mode = ProgrammingMode.Absolute;
}
public virtual void Rotate(double angle) =>
ApplyTransform(code => (code as IMovable)?.Rotate(angle), angle);
public virtual void Rotate(double angle, Vector origin) =>
ApplyTransform(code => (code as IMovable)?.Rotate(angle, origin), angle);
public void Offset(double x, double y) =>
ApplyTransform(code => (code as IMovable)?.Offset(x, y));
public void Offset(Vector voffset) =>
ApplyTransform(code => (code as IMovable)?.Offset(voffset));
private void ApplyTransform(Action<ICode> transform, double? rotationAngle = null)
{
var previousMode = Mode;
SetProgrammingModeAbs();
foreach (var code in this)
{
if (rotationAngle.HasValue && code is SubProgramCall subpgm)
{
subpgm.Loop?.Rotate(rotationAngle.Value);
}
transform(code);
}
if (previousMode == ProgrammingMode.Incremental)
SetProgrammingModeInc();
if (rotationAngle.HasValue)
Rotation = MathHelper.NormalizeAngleRad(Rotation + rotationAngle.Value);
}
public Box GetBoundingBox()
{
var origin = new Vector(0, 0);
return GetBoundingBox(ref origin);
}
private Box GetBoundingBox(ref Vector pos)
{
var bounds = new BoundsTracker();
foreach (var code in this)
{
switch (code)
{
case LinearMove line:
pos = ProcessLinearMotion(line.EndPoint, pos, bounds);
break;
case RapidMove rapid:
pos = ProcessLinearMotion(rapid.EndPoint, pos, bounds);
break;
case CircularMove arc:
pos = ProcessCircularMotion(arc, pos, bounds);
break;
case SubProgramCall subpgm:
var box = subpgm.Loop.GetBoundingBox(ref pos);
bounds.ExpandTo(box);
break;
}
}
return bounds.ToBox();
}
private Vector ProcessLinearMotion(Vector endPoint, Vector pos, BoundsTracker bounds)
{
var pt = Mode == ProgrammingMode.Absolute ? endPoint : endPoint + pos;
bounds.Include(pt);
return pt;
}
private Vector ProcessCircularMotion(CircularMove arc, Vector pos, BoundsTracker bounds)
{
var radius = arc.CenterPoint.DistanceTo(arc.EndPoint);
var (endpt, centerpt) = Mode == ProgrammingMode.Incremental
? (arc.EndPoint + pos, arc.CenterPoint + pos)
: (arc.EndPoint, arc.CenterPoint);
// Start with endpoint bounds
var minX = Math.Min(pos.X, endpt.X);
var maxX = Math.Max(pos.X, endpt.X);
var minY = Math.Min(pos.Y, endpt.Y);
var maxY = Math.Max(pos.Y, endpt.Y);
// Check if arc crosses cardinal directions
var startAngle = MathHelper.NormalizeAngleRad(pos.AngleFrom(centerpt));
var endAngle = MathHelper.NormalizeAngleRad(endpt.AngleFrom(centerpt));
// Switch angles for clockwise arcs
if (arc.Rotation == RotationType.CW)
Generic.Swap(ref startAngle, ref endAngle);
// Expand bounds if arc crosses cardinal points
if (MathHelper.IsAngleBetween(MathHelper.HalfPI, startAngle, endAngle))
maxY = centerpt.Y + radius;
if (MathHelper.IsAngleBetween(Math.PI, startAngle, endAngle))
minX = centerpt.X - radius;
if (MathHelper.IsAngleBetween(Math.PI * 1.5, startAngle, endAngle))
minY = centerpt.Y - radius;
if (MathHelper.IsAngleBetween(MathHelper.TwoPI, startAngle, endAngle))
maxX = centerpt.X + radius;
bounds.Expand(minX, minY, maxX, maxY);
return endpt;
}
public static Program Load(Stream stream)
{
var reader = new ProgramReader();
reader.Read(stream);
return reader.Program;
}
private class BoundsTracker
{
private double minX, minY, maxX, maxY;
public void Include(Vector pt)
{
if (pt.X < minX) minX = pt.X;
if (pt.X > maxX) maxX = pt.X;
if (pt.Y < minY) minY = pt.Y;
if (pt.Y > maxY) maxY = pt.Y;
}
public void Expand(double left, double bottom, double right, double top)
{
if (left < minX) minX = left;
if (right > maxX) maxX = right;
if (bottom < minY) minY = bottom;
if (top > maxY) maxY = top;
}
public void ExpandTo(Box box)
{
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;
}
public Box ToBox() => new(minX, minY, maxX - minX, maxY - minY);
}
}
}
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Models
{
public partial class Report
{
@@ -1,5 +1,5 @@

namespace PepLib
namespace PepLib.Models
{
public partial class Report
{
@@ -1,6 +1,6 @@
using PepLib.IO;
using PepLib.IO;
namespace PepLib
namespace PepLib.Models
{
public partial class Report
{
@@ -118,4 +118,4 @@ namespace PepLib
return true;
}
}
}
}
-364
View File
@@ -1,364 +0,0 @@
using PepLib.Codes;
using PepLib.IO;
namespace PepLib
{
public class Program : List<ICode>, 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;
}
}
}
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Utilities
{
public static class AngleConverter
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Utilities
{
public static class Generic
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Utilities
{
public class IniConfig
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Utilities
{
public static class MathHelper
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Utilities
{
public class Node
{
@@ -1,4 +1,4 @@
namespace PepLib
namespace PepLib.Utilities
{
public static class Tolerance
{
@@ -1,6 +1,6 @@
using System.Diagnostics;
using System.Diagnostics;
namespace PepLib
namespace PepLib.Utilities
{
public static class Util
{
@@ -1,7 +1,7 @@
using System.IO.Compression;
using System.Text.RegularExpressions;
namespace PepLib
namespace PepLib.Utilities
{
public static class ZipHelper
{
@@ -79,4 +79,3 @@ namespace PepLib
}
}
}
+171
View File
@@ -400,4 +400,175 @@ public class PepTools
return $"Error calling PEP API: {ex.Message}";
}
}
[McpServerTool, Description("Get a list of drawings with comprehensive filtering options for all fields including dimensions, dates, and boolean flags.")]
public static async Task<string> GetDrawings(
[Description("Filter by partial name (case-insensitive)")] string? name = null,
[Description("Filter by partial customer name (case-insensitive)")] string? customer = null,
[Description("Filter by partial customer ID (case-insensitive)")] string? custId = null,
[Description("Filter by partial description (case-insensitive)")] string? description = null,
[Description("Filter by partial revision (case-insensitive)")] string? revision = null,
[Description("Filter by partial material (case-insensitive)")] string? material = null,
[Description("Filter by partial material grade (case-insensitive)")] string? materialGrade = null,
[Description("Filter by partial programmer name (case-insensitive)")] string? programmer = null,
[Description("Filter by partial created by (case-insensitive)")] string? createdBy = null,
[Description("Filter by exact status match")] string? status = null,
[Description("Filter by exact type match")] string? type = null,
[Description("Filter by exact application match")] string? application = null,
[Description("Filter by creation date after (yyyy-MM-dd)")] string? createdAfter = null,
[Description("Filter by creation date before (yyyy-MM-dd)")] string? createdBefore = null,
[Description("Filter by modified date after (yyyy-MM-dd)")] string? modifiedAfter = null,
[Description("Filter by modified date before (yyyy-MM-dd)")] string? modifiedBefore = null,
[Description("Filter by minimum width")] double? minWidth = null,
[Description("Filter by maximum width")] double? maxWidth = null,
[Description("Filter by minimum length")] double? minLength = null,
[Description("Filter by maximum length")] double? maxLength = null,
[Description("Filter by minimum area")] double? minArea = null,
[Description("Filter by maximum area")] double? maxArea = null,
[Description("Filter by has bevel")] bool? hasBevel = null,
[Description("Filter by has lead-in")] bool? hasLeadIn = null,
[Description("Filter by has tab")] bool? hasTab = null,
[Description("Number of results to skip (default 0)")] int offset = 0,
[Description("Maximum number of results to return (default 100)")] int limit = 100)
{
try
{
var queryParams = new List<string>();
if (!string.IsNullOrWhiteSpace(name))
queryParams.Add($"name={Uri.EscapeDataString(name)}");
if (!string.IsNullOrWhiteSpace(customer))
queryParams.Add($"customer={Uri.EscapeDataString(customer)}");
if (!string.IsNullOrWhiteSpace(custId))
queryParams.Add($"custId={Uri.EscapeDataString(custId)}");
if (!string.IsNullOrWhiteSpace(description))
queryParams.Add($"description={Uri.EscapeDataString(description)}");
if (!string.IsNullOrWhiteSpace(revision))
queryParams.Add($"revision={Uri.EscapeDataString(revision)}");
if (!string.IsNullOrWhiteSpace(material))
queryParams.Add($"material={Uri.EscapeDataString(material)}");
if (!string.IsNullOrWhiteSpace(materialGrade))
queryParams.Add($"materialGrade={Uri.EscapeDataString(materialGrade)}");
if (!string.IsNullOrWhiteSpace(programmer))
queryParams.Add($"programmer={Uri.EscapeDataString(programmer)}");
if (!string.IsNullOrWhiteSpace(createdBy))
queryParams.Add($"createdBy={Uri.EscapeDataString(createdBy)}");
if (!string.IsNullOrWhiteSpace(status))
queryParams.Add($"status={Uri.EscapeDataString(status)}");
if (!string.IsNullOrWhiteSpace(type))
queryParams.Add($"type={Uri.EscapeDataString(type)}");
if (!string.IsNullOrWhiteSpace(application))
queryParams.Add($"application={Uri.EscapeDataString(application)}");
if (!string.IsNullOrWhiteSpace(createdAfter))
queryParams.Add($"createdAfter={Uri.EscapeDataString(createdAfter)}");
if (!string.IsNullOrWhiteSpace(createdBefore))
queryParams.Add($"createdBefore={Uri.EscapeDataString(createdBefore)}");
if (!string.IsNullOrWhiteSpace(modifiedAfter))
queryParams.Add($"modifiedAfter={Uri.EscapeDataString(modifiedAfter)}");
if (!string.IsNullOrWhiteSpace(modifiedBefore))
queryParams.Add($"modifiedBefore={Uri.EscapeDataString(modifiedBefore)}");
if (minWidth.HasValue)
queryParams.Add($"minWidth={minWidth.Value}");
if (maxWidth.HasValue)
queryParams.Add($"maxWidth={maxWidth.Value}");
if (minLength.HasValue)
queryParams.Add($"minLength={minLength.Value}");
if (maxLength.HasValue)
queryParams.Add($"maxLength={maxLength.Value}");
if (minArea.HasValue)
queryParams.Add($"minArea={minArea.Value}");
if (maxArea.HasValue)
queryParams.Add($"maxArea={maxArea.Value}");
if (hasBevel.HasValue)
queryParams.Add($"hasBevel={hasBevel.Value.ToString().ToLower()}");
if (hasLeadIn.HasValue)
queryParams.Add($"hasLeadIn={hasLeadIn.Value.ToString().ToLower()}");
if (hasTab.HasValue)
queryParams.Add($"hasTab={hasTab.Value.ToString().ToLower()}");
queryParams.Add($"offset={offset}");
queryParams.Add($"limit={limit}");
var query = "?" + string.Join("&", queryParams);
var response = await _httpClient.GetAsync($"/drawings{query}");
if (!response.IsSuccessStatusCode)
return $"Error: {response.StatusCode} - {await response.Content.ReadAsStringAsync()}";
var json = await response.Content.ReadAsStringAsync();
return json;
}
catch (Exception ex)
{
return $"Error calling PEP API: {ex.Message}";
}
}
[McpServerTool, Description("Get detailed information about a specific drawing by its ID.")]
public static async Task<string> GetDrawing(
[Description("The drawing ID to look up")] int id)
{
try
{
var response = await _httpClient.GetAsync($"/drawings/{id}");
if (!response.IsSuccessStatusCode)
return $"Error: {response.StatusCode} - {await response.Content.ReadAsStringAsync()}";
var json = await response.Content.ReadAsStringAsync();
return json;
}
catch (Exception ex)
{
return $"Error calling PEP API: {ex.Message}";
}
}
[McpServerTool, Description("Get detailed information about a specific drawing by its exact name.")]
public static async Task<string> GetDrawingByName(
[Description("The exact drawing name to look up")] string name)
{
try
{
var response = await _httpClient.GetAsync($"/drawings/name/{Uri.EscapeDataString(name)}");
if (!response.IsSuccessStatusCode)
return $"Error: {response.StatusCode} - {await response.Content.ReadAsStringAsync()}";
var json = await response.Content.ReadAsStringAsync();
return json;
}
catch (Exception ex)
{
return $"Error calling PEP API: {ex.Message}";
}
}
[McpServerTool, Description("Search for drawings by partial name match. Returns matching drawings with basic information.")]
public static async Task<string> SearchDrawings(
[Description("The partial drawing name to search for")] string searchTerm,
[Description("Maximum number of results to return (default 100)")] int limit = 100)
{
try
{
var queryParams = new List<string>
{
$"search={Uri.EscapeDataString(searchTerm)}",
$"limit={limit}"
};
var query = "?" + string.Join("&", queryParams);
var response = await _httpClient.GetAsync($"/drawings/search{query}");
if (!response.IsSuccessStatusCode)
return $"Error: {response.StatusCode} - {await response.Content.ReadAsStringAsync()}";
var json = await response.Content.ReadAsStringAsync();
return json;
}
catch (Exception ex)
{
return $"Error calling PEP API: {ex.Message}";
}
}
}