using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
// 解决Exception命名冲突
using SysException = System.Exception;
using AcException = Autodesk.AutoCAD.Runtime.Exception;
namespace GridLinePlugin
{
public class GridLineCommands
{
// 固定线段长度选项(毫米)
private static readonly double[] FixedLengths = { 300, 600, 900, 1200, 1500, 1800 };
private const string LAYER_NAME = "盘扣轴网";
// 参数记忆静态变量
private static double _lastOffsetX = 0.0;
private static double _lastOffsetY = 0.0;
private static double _lastStartLengthX = 900.0;
private static double _lastStartLengthY = 1500.0;
// 辅助方法
private double GetOffset(string message, double defaultValue, Editor ed)
{
string formattedMessage = string.Format(message, defaultValue);
PromptDoubleOptions opts = new PromptDoubleOptions(formattedMessage)
{
AllowNegative = true,
AllowZero = true,
DefaultValue = defaultValue,
UseDefaultValue = true
};
PromptDoubleResult res = ed.GetDouble(opts);
return res.Status == PromptStatus.OK ? res.Value : defaultValue;
}
private double GetSegmentLength(string message, double defaultValue, Editor ed)
{
string formattedMessage = string.Format(message, defaultValue);
PromptDoubleOptions opts = new PromptDoubleOptions(formattedMessage)
{
AllowNegative = false,
AllowZero = false,
AllowNone = false,
DefaultValue = defaultValue,
UseDefaultValue = true
};
PromptDoubleResult res;
do
{
res = ed.GetDouble(opts);
if (res.Status != PromptStatus.OK) return defaultValue;
if (res.Value <= 0)
{
ed.WriteMessage("\n长度必须大于0! 请重新输入: ");
}
} while (res.Value <= 0);
return res.Value;
}
[CommandMethod("DG", CommandFlags.Modal)]
public void DrawGridInteractive()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
try
{
// 1. 获取偏移值
double offsetX = GetOffset("\nX方向偏移值 (mm) <{0}>: ", _lastOffsetX, ed);
double offsetY = GetOffset("\nY方向偏移值 (mm) <{0}>: ", _lastOffsetY, ed);
// 2. 获取起始长度
double startLengthX = GetSegmentLength("\n横向起始线段长度 (mm) <{0}>: ", _lastStartLengthX, ed);
double startLengthY = GetSegmentLength("\n纵向起始线段长度 (mm) <{0}>: ", _lastStartLengthY, ed);
// 更新记忆参数
_lastOffsetX = offsetX;
_lastOffsetY = offsetY;
_lastStartLengthX = startLengthX;
_lastStartLengthY = startLengthY;
// 3. 获取起始点
PromptPointResult startPtRes = ed.GetPoint("\n选择网格起始点: ");
if (startPtRes.Status != PromptStatus.OK) return;
Point3d basePoint = startPtRes.Value;
// 应用偏移
Point3d actualStartPoint = basePoint + new Vector3d(offsetX, offsetY, 0);
// 4. 创建并运行拖拽器
GridJig jig = new GridJig(actualStartPoint, startLengthX, startLengthY, doc);
PromptResult jigResult = ed.Drag(jig);
if (jigResult.Status == PromptStatus.OK)
{
jig.CommitGrid(LAYER_NAME);
int shortLines = jig.GetShortLineCount(300.0);
if (shortLines > 0)
{
ed.WriteMessage($"\n警告: 有 {shortLines} 条线段长度小于300mm!");
}
ed.WriteMessage($"\n成功绘制网格! 共生成 {jig.LineCount} 条线段");
}
}
catch (SysException ex)
{
ed.WriteMessage($"\n错误: {ex.Message}");
}
}
// 网格拖拽器类
private class GridJig : DrawJig
{
private readonly Point3d _startPoint;
private Point3d _currentPoint;
private readonly double _startLengthX;
private readonly double _startLengthY;
private readonly Document _doc;
private readonly List<Line> _lines = new List<Line>();
private List<double> _xSegments = new List<double>();
private List<double> _ySegments = new List<double>();
public int LineCount => _lines.Count;
public int GetShortLineCount(double minLength)
{
return _lines.Count(line => line.Length < minLength);
}
public GridJig(Point3d startPoint, double startLengthX, double startLengthY, Document doc)
{
_startPoint = startPoint;
_currentPoint = startPoint;
_startLengthX = startLengthX;
_startLengthY = startLengthY;
_doc = doc;
}
// 实现抽象成员
protected override SamplerStatus Sampler(JigPrompts prompts)
{
JigPromptPointOptions opts = new JigPromptPointOptions("\n指定网格终点或输入长度: ")
{
UserInputControls = UserInputControls.Accept3dCoordinates |
UserInputControls.NoZeroResponseAccepted |
UserInputControls.NoNegativeResponseAccepted,
BasePoint = _startPoint,
UseBasePoint = true,
Cursor = CursorType.RubberBand
};
PromptPointResult result = prompts.AcquirePoint(opts);
if (result.Status == PromptStatus.Cancel)
return SamplerStatus.Cancel;
if (_currentPoint.DistanceTo(result.Value) < 0.001)
return SamplerStatus.NoChange;
_currentPoint = result.Value;
return SamplerStatus.OK;
}
protected override bool WorldDraw(WorldDraw draw)
{
try
{
// 清除临时图形
foreach (var line in _lines)
{
if (!line.IsDisposed) line.Dispose();
}
_lines.Clear();
// 计算方向向量
Vector3d delta = _currentPoint - _startPoint;
double dx = delta.X;
double dy = delta.Y;
// 计算总长度和方向
double totalX = Math.Abs(dx);
double totalY = Math.Abs(dy);
int signX = Math.Sign(dx);
int signY = Math.Sign(dy);
// 生成分段点 - 使用指定的起始长度
_xSegments = GenerateSegments(totalX, _startLengthX, true);
_ySegments = GenerateSegments(totalY, _startLengthY, false);
// 计算实际终点
Point3d actualEndPoint = new Point3d(
_startPoint.X + signX * _xSegments.Last(),
_startPoint.Y + signY * _ySegments.Last(),
_startPoint.Z
);
// 绘制横向网格线
DrawHorizontalLines(signX, signY, actualEndPoint, draw);
// 绘制纵向网格线
DrawVerticalLines(signX, signY, actualEndPoint, draw);
}
catch (SysException ex)
{
_doc.Editor.WriteMessage($"\n绘图错误: {ex.Message}");
}
return true;
}
// 分段生成算法
private List<double> GenerateSegments(double totalLength, double spacing, bool isXDirection)
{
List<double> segments = new List<double> { 0 };
if (totalLength <= 0) return segments;
double currentPos = 0;
int segmentCount = 0;
// 优先使用起始长度进行连续布置
while (currentPos < totalLength && segmentCount < 100)
{
// 尝试使用起始长度
if (currentPos + spacing <= totalLength)
{
currentPos += spacing;
segments.Add(currentPos);
segmentCount++;
continue;
}
// 起始长度不适用时,尝试固定长度
double maxFixed = FixedLengths
.Where(len => currentPos + len <= totalLength)
.DefaultIfEmpty(0)
.Max();
if (maxFixed >= 300)
{
currentPos += maxFixed;
segments.Add(currentPos);
segmentCount++;
}
else
{
// 如果固定长度也不适用,尝试剩余长度
double remaining = totalLength - currentPos;
if (remaining >= 300)
{
currentPos = totalLength;
segments.Add(currentPos);
}
break;
}
}
// 确保包含终点(如果剩余长度不足300mm则跳过)
if (segments.Last() < totalLength && (totalLength - segments.Last()) >= 300)
{
segments.Add(totalLength);
}
// 确保至少有两个分段点
if (segments.Count < 2)
{
segments.Add(totalLength);
}
return segments;
}
// 绘制横向线
private void DrawHorizontalLines(int signX, int signY, Point3d actualEndPoint, WorldDraw draw)
{
if (_ySegments.Count == 0) return;
for (int i = 0; i < _ySegments.Count; i++)
{
double yPos = _ySegments[i];
Point3d start = _startPoint + new Vector3d(0, signY * yPos, 0);
// 终点自动修剪到实际终点
Point3d end = new Point3d(actualEndPoint.X, start.Y, start.Z);
Line line = new Line(start, end);
line.ColorIndex = 1;
if (line.Length < 0.001) continue;
if (!IsOverlapping(line))
{
_lines.Add(line);
draw.Geometry.Draw(line);
}
}
}
// 绘制纵向线
private void DrawVerticalLines(int signX, int signY, Point3d actualEndPoint, WorldDraw draw)
{
if (_xSegments.Count == 0) return;
for (int i = 0; i < _xSegments.Count; i++)
{
double xPos = _xSegments[i];
Point3d start = _startPoint + new Vector3d(signX * xPos, 0, 0);
// 终点自动修剪到实际终点
Point3d end = new Point3d(start.X, actualEndPoint.Y, start.Z);
Line line = new Line(start, end);
line.ColorIndex = 1;
if (line.Length < 0.001) continue;
if (!IsOverlapping(line))
{
_lines.Add(line);
draw.Geometry.Draw(line);
}
}
}
// 重叠检测方法
private bool IsOverlapping(Line newLine)
{
const double toleranceValue = 0.1;
Tolerance tolerance = new Tolerance(toleranceValue, toleranceValue);
foreach (Line existingLine in _lines)
{
bool sameStart = newLine.StartPoint.IsEqualTo(existingLine.StartPoint, tolerance) ||
newLine.StartPoint.IsEqualTo(existingLine.EndPoint, tolerance);
bool sameEnd = newLine.EndPoint.IsEqualTo(existingLine.StartPoint, tolerance) ||
newLine.EndPoint.IsEqualTo(existingLine.EndPoint, tolerance);
if (sameStart && sameEnd)
{
return true;
}
}
return false;
}
// 提交网格到图纸
public void CommitGrid(string layerName)
{
using (Transaction tr = _doc.Database.TransactionManager.StartTransaction())
{
try
{
BlockTable bt = tr.GetObject(_doc.Database.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
// 创建图层
LayerTable lt = tr.GetObject(_doc.Database.LayerTableId, OpenMode.ForRead) as LayerTable;
if (!lt.Has(layerName))
{
lt.UpgradeOpen();
LayerTableRecord layer = new LayerTableRecord
{
Name = layerName,
Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(
Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 1)
};
lt.Add(layer);
tr.AddNewlyCreatedDBObject(layer, true);
}
// 添加所有线段(最终修剪)
foreach (Line line in _lines)
{
if (!line.IsDisposed)
{
// 精确修剪到网格边界
TrimToGridBoundary(line);
// 跳过小于300mm的线段
if (line.Length < 300) continue;
line.Layer = layerName;
line.ColorIndex = 256; // ByLayer
btr.AppendEntity(line);
tr.AddNewlyCreatedDBObject(line, true);
}
}
tr.Commit();
}
catch (SysException)
{
tr.Abort();
throw;
}
}
}
// 精确修剪线段到网格边界
private void TrimToGridBoundary(Line line)
{
// 计算实际网格边界
double maxX = _xSegments.Last();
double maxY = _ySegments.Last();
// 获取线段的实际方向
Vector3d direction = line.EndPoint - line.StartPoint;
// 横向线修剪到最大Y位置
if (Math.Abs(direction.X) > Math.Abs(direction.Y))
{
double currentY = Math.Abs(line.EndPoint.Y - _startPoint.Y);
if (currentY > maxY)
{
line.EndPoint = new Point3d(
line.EndPoint.X,
_startPoint.Y + Math.Sign(direction.Y) * maxY,
line.EndPoint.Z);
}
}
// 纵向线修剪到最大X位置
else
{
double currentX = Math.Abs(line.EndPoint.X - _startPoint.X);
if (currentX > maxX)
{
line.EndPoint = new Point3d(
_startPoint.X + Math.Sign(direction.X) * maxX,
line.EndPoint.Y,
line.EndPoint.Z);
}
}
}
}
}
}
在以上代码基础上做一下改进,要求在运行功能的第一步输入偏移值前面增加一个步骤要求先指定一根控制线作为之后布网线的角度控制,或者画一根控制线作为之后布网线的角度控制,到布网线步骤时必须根据之前画好的或指定的线作为布置网线的引导方向布置网线,
按以上要求将修改完整