Hi,
As there's neither AutoLISP, nor COM, nor .NET API to create a dynamic bloc by code, I assume the "rectangle" dynamic block already exists in the drawing (see attached rectangle.dwg).
Here's a C# example, which checks for rectangular polyline validity whatever the rectangle rotation and plane.
This can be converted to LISP, but I'm more cumfortable with .NET than with LISP these days (more accurately with Visual Studio than with the Visual LISP IDE)
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System.Linq;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
[assembly: CommandClass(typeof(RectangleSample.Commands))]
namespace RectangleSample
{
public class Commands
{
const string blockName = "rectangle";
const string distX = "Length";
const string distY = "Width";
[CommandMethod("TEST")]
public void Test()
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var opts = new PromptStringOptions("\nEnter the layer name: ");
opts.AllowSpaces = true;
var rslt = ed.GetString(opts);
if (rslt.Status != PromptStatus.OK)
return;
var layerName = rslt.StringResult;
using (var tr = db.TransactionManager.StartTransaction())
{
var lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
if (!lt.Has(layerName))
{
ed.WriteMessage($"\nLayer '{layerName}' not found.");
return;
}
var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
if (!bt.Has(blockName))
{
ed.WriteMessage($"\nBlock '{blockName}' not found.");
return;
}
var model = (BlockTableRecord)tr.GetObject(
SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);
var plines = model
.Cast<ObjectId>()
.Where(id => id.ObjectClass.DxfName == "LWPOLYLINE")
.Select(id => (Polyline)tr.GetObject(id, OpenMode.ForRead))
.Where(pl => pl.Layer == layerName);
foreach (var pline in plines)
{
Point2d origin;
double length, width, rotation;
if (TryGetRectangle(pline, out origin, out length, out width, out rotation))
{
var insPt = new Point3d(origin.X, origin.Y, 0.0);
var br = new BlockReference(insPt, bt[blockName]);
br.Layer = layerName;
br.TransformBy(
Matrix3d.PlaneToWorld(new Plane(Point3d.Origin, pline.Normal)) *
Matrix3d.Displacement(new Vector3d(0.0, 0.0, pline.Elevation)) *
Matrix3d.Rotation(rotation, Vector3d.ZAxis, insPt));
model.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
foreach (DynamicBlockReferenceProperty prop in br.DynamicBlockReferencePropertyCollection)
{
switch (prop.PropertyName)
{
case distX: prop.Value = length; break;
case distY: prop.Value = width; break;
default: break;
}
}
pline.UpgradeOpen();
pline.Erase();
}
}
tr.Commit();
}
}
private bool IsRectangular(Polyline pline)
{
if (pline == null)
return false;
if (!pline.Closed)
return false;
if (pline.NumberOfVertices != 4)
return false;
if (Enumerable.Range(0, 4)
.Select(i => pline.GetBulgeAt(i))
.Any(b => b != 0.0))
return false;
var s1 = pline.GetLineSegment2dAt(0);
var s2 = pline.GetLineSegment2dAt(1);
var s3 = pline.GetLineSegment2dAt(2);
var s4 = pline.GetLineSegment2dAt(3);
return
s1.IsParallelTo(s3) &&
s2.IsParallelTo(s4) &&
s1.IsPerpendicularTo(s2);
}
private bool TryGetRectangle(Polyline pline, out Point2d origin, out double length, out double width, out double rotation)
{
if (IsRectangular(pline))
{
var pts = Enumerable.Range(0, 4)
.Select(n => pline.GetPoint2dAt(n))
.ToList();
if (!pts[0].GetVectorTo(pts[1]).GetPerpendicularVector().IsCodirectionalTo(pts[1].GetVectorTo(pts[2])))
pts.Reverse();
origin = pts.OrderBy(p => p.Y).ThenBy(p => p.X).First();
int i = pts.IndexOf(origin);
length = origin.GetDistanceTo(i == 3 ? pts[0] : pts[i + 1]);
width = origin.GetDistanceTo(i == 0 ? pts[3] : pts[i - 1]);
rotation = origin.GetVectorTo(i == 3 ? pts[0] : pts[i + 1]).Angle;
return true;
}
else
{
origin = Point2d.Origin;
length = 0.0;
width = 0.0;
rotation = 0.0;
return false;
}
}
}
}