1. Requirements Analysis
In CAD development, we often need to implement these functionalities:
- Allow users to click multiple points to automatically draw polylines
- Enable users to click multiple points and automatically draw graphics at those locations
- Remove blocks that intersect with lines or graphics
2. Automated Polyline Drawing
Implementation Approach:
- Prompt the user to select the entire area of operation
- Use selection filters to identify all blocks within the specified layer
- Create a dedicated layer for polylines
- Initiate a loop for drawing multiple polylines
- For each polyline, recursively collect point selections from the user
- Analyze the collected points to determine the optimal connection path
- Draw the polyline on the designated layer
- Utilize CAD's IntersectWith API to detect intersections with blocks
- Remove any blocks that intersect with the polyline
Code Implementation:
/// <summary>
/// Creates polylines based on user input and removes intersecting blocks
/// </summary>
[CommandMethod("CREATEPL")]
public void CreatePolylines()
{
string targetLayer = CommonConstant.PHALANX_DIVISION_LAYER;
var doc = Application.DocumentManager.MdiActiveDocument;
Editor editor = doc.Editor;
Database db = doc.Database;
// Filter selection to find all blocks in the specified layer
TypedValue[] filters = {
new TypedValue((int)DxfCode.Start, "INSERT"),
new TypedValue((int)DxfCode.LayerName, targetLayer)
};
SelectionFilter selectionFilter = new SelectionFilter(filters);
PromptSelectionResult selectionResult = editor.GetSelection(selectionFilter);
if (selectionResult.Status == PromptStatus.OK)
{
// Get all selected blocks
SelectionSet selectedSet = selectionResult.Value;
editor.WriteMessage("\nTotal blocks selected: {0}", selectedSet.Count);
List<BlockReference> blockRefs = new List<BlockReference>();
using (Transaction ts = db.TransactionManager.StartTransaction())
{
foreach (SelectedObject selectedObj in selectedSet)
{
BlockReference blockRef = selectedObj.ObjectId.GetObject(OpenMode.ForWrite) as BlockReference;
blockRefs.Add(blockRef);
}
ts.Commit();
}
// Create new layer for polylines
AddLayerResult layerResult = LayerTool.AddLayer(db, CommonConstant.ROAD_LAYER);
int polylineCounter = 1;
bool continueDrawing = true;
while (continueDrawing)
{
int nodeCounter = 1;
PromptPointOptions pointOptions = new PromptPointOptions("\nStart point for polyline " + polylineCounter + ", node " + nodeCounter + ":");
PromptPointResult pointResult = editor.GetPoint(pointOptions);
List<Point3d> polylineNodes = new List<Point3d>();
if (pointResult.Status == PromptStatus.OK)
{
polylineNodes.Add(pointResult.Value);
pointService.CollectPoints(polylineNodes, polylineCounter, nodeCounter, editor);
drawingService.CreateAndCleanPolyline(blockRefs, polylineNodes, layerResult.layerName);
}
else
{
continueDrawing = false;
}
polylineCounter++;
}
}
}
/// <summary>
/// Collects points from user for polyline creation
/// </summary>
/// <param name="collectedPoints">List of points collected so far</param>
/// <param name="polylineIndex">Current polyline number</param>
/// <param name="nodeCount">Number of nodes collected</param>
/// <param name="editor">CAD editor interface</param>
public void CollectPoints(List<Point3d> collectedPoints, int polylineIndex, int nodeCount, Editor editor)
{
nodeCount++;
PromptPointOptions pointOptions = new PromptPointOptions("\nSelect point " + polylineIndex + ", node " + nodeCount + ":");
PromptPointResult pointResult = editor.GetPoint(pointOptions);
if (pointResult.Status == PromptStatus.OK)
{
collectedPoints.Add(pointResult.Value);
CollectPoints(collectedPoints, polylineIndex, nodeCount, editor);
}
}
/// <summary>
/// Creates polyline and removes intersecting blocks
/// </summary>
/// <param name="blockReferences">List of blocks to check for intersections</param>
/// <param name="polylinePoints">Points defining the polyline</param>
/// <param name="layerName">Name of the layer for the polyline</param>
public void CreateAndCleanPolyline(List<BlockReference> blockReferences, List<Point3d> polylinePoints, string layerName)
{
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
if (blockReferences.Count > 0)
{
// Determine optimal connection path
polylinePoints = geometryTool.OptimizePath(polylinePoints);
List<Point2d> points2D = polylinePoints.Select(p => new Point2d(p.X, p.Y)).ToList();
// Draw the polyline
ObjectId polylineId = db.AddPolylineToModelSpace(false, 10, layerName, points2D.ToArray());
// Remove blocks that intersect with the polyline
DBObject dbObject = tr.GetObject(polylineId, OpenMode.ForWrite);
if (dbObject is Polyline)
{
Polyline polyline = (Polyline)dbObject;
List<Point3d> intersectionPoints = new List<Point3d>();
for (var i = 0; i < blockReferences.Count; i++)
{
Point3dCollection intersections = new Point3dCollection();
polyline.IntersectWith(blockReferences[i], Intersect.OnBothOperands, intersections, IntPtr.Zero, IntPtr.Zero);
if (intersections.Count > 0)
{
intersectionPoints.Add(blockReferences[i].Position);
}
}
if (intersectionPoints.Count > 0)
{
blockManager.RemoveBlocksByLocation(db, CommonConstant.BRACKET_BLOCK_NAME, intersectionPoints);
}
}
}
tr.Commit();
}
}
3. Drawing Graphics at Specified Points
Implementation Approach:
- Similar to polyline drawing but focuses on creating graphics at specific points
- Uses selection filters to identify blocks in the target area
- Creates a new layer for the graphics
- Collects points from user input
- Generates graphics at each specified point
- Checks for intersections and removes conflicting blocks
Code Implementation:
/// <summary>
/// Creates graphics at user-specified points
/// </summary>
[CommandMethod("DRAWGP")]
public void CreatePointGraphics()
{
string targetLayer = CommonConstant.PHALANX_DIVISION_LAYER;
var doc = Application.DocumentManager.MdiActiveDocument;
Editor editor = doc.Editor;
Database db = doc.Database;
// Filter selection to find all blocks in the specified layer
TypedValue[] filters = {
new TypedValue((int)DxfCode.Start, "INSERT"),
new TypedValue((int)DxfCode.LayerName, targetLayer)
};
SelectionFilter selectionFilter = new SelectionFilter(filters);
PromptSelectionResult selectionResult = editor.GetSelection(selectionFilter);
if (selectionResult.Status == PromptStatus.OK)
{
// Get all selected blocks
SelectionSet selectedSet = selectionResult.Value;
editor.WriteMessage("\nTotal blocks selected: {0}", selectedSet.Count);
List<BlockReference> blockRefs = new List<BlockReference>();
using (Transaction ts = db.TransactionManager.StartTransaction())
{
foreach (SelectedObject selectedObj in selectedSet)
{
BlockReference blockRef = selectedObj.ObjectId.GetObject(OpenMode.ForWrite) as BlockReference;
blockRefs.Add(blockRef);
}
ts.Commit();
}
// Create new layer for graphics
AddLayerResult layerResult = LayerTool.AddLayer(db, CommonConstant.TRANSFORMER_LAYER);
graphicsGenerator.GenerateAtPoints(blockRefs, layerResult, doc);
}
}
/// <summary>
/// Generates graphics at specified points and removes intersecting blocks
/// </summary>
/// <param name="blockReferences">List of blocks to check for intersections</param>
/// <param name="layerInfo">Layer information for the graphics</param>
/// <param name="document">CAD document reference</param>
public void GenerateAtPoints(List<BlockReference> blockReferences, AddLayerResult layerInfo, Document document)
{
if (blockReferences.Count > 0)
{
Editor editor = document.Editor;
Database db = document.Database;
// Group blocks by color
var blockGroups = blockReferences.GroupBy(reference => reference.Color)
.ToDictionary(group => group.Key,
group => group.ToList());
int groupCount = blockGroups.Count;
List<Point3d> graphicPoints = new List<Point3d>();
// Collect points from user
while (groupCount > 0)
{
PromptPointOptions pointOptions = new PromptPointOptions("\nSelect location for graphic " + groupCount);
PromptPointResult pointResult = editor.GetPoint(pointOptions);
if (pointResult.Status == PromptStatus.OK)
{
graphicPoints.Add(pointResult.Value);
}
groupCount--;
}
// Generate graphics at each point
foreach (var point in graphicPoints)
{
Dictionary blockProperties = blockTool.GetMaximumBlockDimensions(db, blockReferences[0]);
ObjectId graphicId = db.AddPolygonToModelSpace(
new Point2d(point.X, point.Y),
blockProperties["maxXSpacing"] / 2,
5,
90,
layerInfo.layerName);
using (Transaction tr = db.TransactionManager.StartTransaction())
{
DBObject dbObject = tr.GetObject(graphicId, OpenMode.ForWrite);
if (dbObject is Polyline)
{
Polyline graphic = (Polyline)dbObject;
List<Point3d> intersectionPoints = new List<Point3d>();
// Check for intersections with blocks
for (var i = 0; i < blockReferences.Count; i++)
{
Point3dCollection intersections = new Point3dCollection();
graphic.IntersectWith(blockReferences[i], Intersect.OnBothOperands, intersections, IntPtr.Zero, IntPtr.Zero);
if (intersections.Count > 0)
{
intersectionPoints.Add(blockReferences[i].Position);
}
}
// Remove intersecting blocks if any
if (intersectionPoints.Count > 0)
{
blockTool.RemoveBlocksByLocation(db, CommonConstant.BRACKET_BLOCK_NAME, intersectionPoints);
}
// Add label text
textTool.AddText(db, "GRAPHIC", new Point2d(point.X, point.Y), blockProperties["maxYSpacing"], layerInfo.layerName);
}
tr.Commit();
}
}
}
}