public class DynamicBlockAlignmentJig : EntityJig
{
#region Fields
private int mCurJigFactorNumber = 1;
private bool mIsDynamicAlignment = false;
private double mAlignmentAngle = 0.0;
private ObjectId mObjectIdToAlignWith = ObjectId.Null;
private double mAngleOffset = 0.0;
private Point3d mPosition
= new Point3d
(0,
0,
0); // Factor #1 private double mRotation = 0.0; // Factor #2
private double mScaleFactor = 1.0; // Factor #3
private static ObjectId pickBlockRefId = ObjectId.Null;
#endregion
#region Constructors
public DynamicBlockAlignmentJig(BlockReference ent)
: base(ent)
{
mAngleOffset = ent.Rotation;
if (ent.IsDynamicBlock)
mIsDynamicAlignment = true;
}
#endregion
#region Properties
protected static Editor CurEditor
{
get
{
return Autodesk.AutoCAD.ApplicationServices.Core.Application.DocumentManager.MdiActiveDocument.Editor;
}
}
protected static Matrix3d UCS
{
get
{
return CurEditor.CurrentUserCoordinateSystem;
}
}
protected new BlockReference Entity
{
get
{
return (BlockReference)base.Entity;
}
}
#endregion
#region Overrides
protected override bool Update()
{
switch (mCurJigFactorNumber)
{
case 1:
Entity.Position = mPosition.TransformBy(UCS);
if (mIsDynamicAlignment && !mObjectIdToAlignWith.IsNull)
{
using (Transaction tr = Entity.Database.TransactionManager.StartTransaction())
{
DBObject obj = tr.GetObject(mObjectIdToAlignWith, OpenMode.ForRead);
{
Matrix3d transform = Matrix3d.Identity;
if (!pickBlockRefId.IsNull) // Check if the subentity is part of a block
{
BlockReference blockRef = tr.GetObject(pickBlockRefId, OpenMode.ForRead) as BlockReference;
if (blockRef != null)
{
transform = blockRef.BlockTransform;
}
}
curve = (Curve)curve.GetTransformedCopy(transform);
Point3d closestPoint = curve.GetClosestPointTo(Entity.Position, false);
Vector3d dir = curve.GetFirstDerivative(closestPoint).TransformBy(UCS.Inverse());
mAlignmentAngle = Vector3d.XAxis.GetAngleTo(dir, Vector3d.ZAxis);
Entity.Rotation = mAlignmentAngle + mAngleOffset;
}
else
{
mObjectIdToAlignWith = ObjectId.Null;
}
tr.Commit();
}
}
break;
// Other cases remain unchanged
}
return true;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
switch (mCurJigFactorNumber)
{
case 1:
JigPromptPointOptions prOptions1
= new JigPromptPointOptions
("\nBlock insertion point:"); PromptPointResult prResult1 = prompts.AcquirePoint(prOptions1);
if (prResult1.Status == PromptStatus.Cancel)
return SamplerStatus.Cancel;
Point3d tempPt = prResult1.Value.TransformBy(UCS.Inverse());
if (tempPt.IsEqualTo(mPosition))
{
return SamplerStatus.NoChange;
}
else
{
mPosition = tempPt;
mObjectIdToAlignWith = pickObjId;
return SamplerStatus.OK;
}
case 2:
JigPromptAngleOptions prOptions2
= new JigPromptAngleOptions
("\nBlock rotation angle:"); prOptions2.BasePoint = mPosition.TransformBy(UCS);
prOptions2.UseBasePoint = true;
PromptDoubleResult prResult2 = prompts.AcquireAngle(prOptions2);
if (prResult2.Status == PromptStatus.Cancel)
return SamplerStatus.Cancel;
if (prResult2.Value.Equals(mRotation))
{
return SamplerStatus.NoChange;
}
else
{
mRotation = prResult2.Value;
return SamplerStatus.OK;
}
case 3:
JigPromptDistanceOptions prOptions3
= new JigPromptDistanceOptions
("\nBlock scale factor:"); prOptions3.BasePoint = mPosition.TransformBy(UCS);
prOptions3.UseBasePoint = true;
PromptDoubleResult prResult3 = prompts.AcquireDistance(prOptions3);
if (prResult3.Status == PromptStatus.Cancel)
return SamplerStatus.Cancel;
if (prResult3.Value.Equals(mScaleFactor))
{
return SamplerStatus.NoChange;
}
else
{
mScaleFactor = prResult3.Value;
return SamplerStatus.OK;
}
default:
break;
}
return SamplerStatus.OK;
}
#endregion
#region Point Monitor
private static ObjectId pickObjId = ObjectId.Null;
private static void Editor_PointMonitor(object sender, PointMonitorEventArgs e)
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
if (e.Context == null)
{
return;
}
FullSubentityPath[] fullEntPath = e.Context.GetPickedEntities();
if (fullEntPath.Length > 0)
{
try
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Entity topLevelEntity = tr.GetObject(fullEntPath.First().GetObjectIds().First(), OpenMode.ForRead) as Entity;
Point3d cursorPosition = e.Context.ComputedPoint;
if (topLevelEntity
is BlockReference blockRef
) {
BlockTableRecord blockDef = tr.GetObject(blockRef.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId entId in blockDef)
{
Entity subEntity = tr.GetObject(entId, OpenMode.ForRead) as Entity;
if (IsCursorOnEntity(subEntity, cursorPosition, blockRef, tr))
{
pickObjId = subEntity.ObjectId;
pickBlockRefId = blockRef.ObjectId; // Store the block reference ObjectId
break;
}
}
}
else
{
pickObjId = topLevelEntity.ObjectId;
pickBlockRefId = ObjectId.Null; // Reset the block reference ObjectId
}
tr.Commit();
}
}
catch (System.Exception ex)
{
pickObjId = ObjectId.Null;
pickBlockRefId = ObjectId.Null;
}
}
else
{
pickObjId = ObjectId.Null;
pickBlockRefId = ObjectId.Null;
}
}
#endregion
// Helper method to check if the cursor is on the entity within a block reference
private static bool IsCursorOnEntity(Entity entity, Point3d cursorPosition, BlockReference blockRef, Transaction tr)
{
// Adjust tolerance as needed
double tolerance = 0.01;
// Transform the cursor position from WCS to the block reference's ECS
Matrix3d transform = blockRef.BlockTransform.Inverse();
Point3d transformedCursorPosition = cursorPosition.TransformBy(transform);
if (entity
is Curve curve
) {
// Get the closest point on the curve to the transformed cursor position
Point3d closestPoint = curve.GetClosestPointTo(transformedCursorPosition, false);
// Check if the distance between the closest point and the transformed cursor position is within the tolerance
return transformedCursorPosition.DistanceTo(closestPoint) <= tolerance;
}
else
{
// For non-curve entities, check if the transformed cursor position is within the entity's geometric extents
Extents3d extents = entity.GeometricExtents;
return transformedCursorPosition.X >= extents.MinPoint.X - tolerance &&
transformedCursorPosition.X <= extents.MaxPoint.X + tolerance &&
transformedCursorPosition.Y >= extents.MinPoint.Y - tolerance &&
transformedCursorPosition.Y <= extents.MaxPoint.Y + tolerance &&
transformedCursorPosition.Z >= extents.MinPoint.Z - tolerance &&
transformedCursorPosition.Z <= extents.MaxPoint.Z + tolerance;
}
}
#region Method to Call
public static bool Jig(BlockReference ent)
{
try
{
DynamicBlockAlignmentJig jigger
= new DynamicBlockAlignmentJig
(ent
); PromptResult pr;
do
{
pr = CurEditor.Drag(jigger);
if (jigger.mCurJigFactorNumber == 1 && jigger.mIsDynamicAlignment && !jigger.mObjectIdToAlignWith.IsNull)
jigger.mCurJigFactorNumber++;
} while (pr.Status != PromptStatus.Cancel && pr.Status != PromptStatus.Error && jigger.mCurJigFactorNumber++ <= 3);
return pr.Status == PromptStatus.OK;
}
catch
{
return false;
}
}
#endregion
#region Test Command
[CommandMethod("DynamicBlockAlignmentJig")]
public static void BlockAttributeJig_Method()
{
Database db = HostApplicationServices.WorkingDatabase;
try
{
string pr = "ROUND_TAKEOFF_SIDE";
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
if (!bt.Has(pr))
{
CurEditor.WriteMessage("\nThe block <{0}> does not exist.", pr);
return;
}
BlockTableRecord btr = tr.GetObject(bt[pr], OpenMode.ForRead) as BlockTableRecord;
using (BlockReference ent
= new BlockReference
(new Point3d
(0,
0,
0), btr
.ObjectId)) {
ent.TransformBy(UCS);
BlockTableRecord modelspace = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
modelspace.AppendEntity(ent);
tr.AddNewlyCreatedDBObject(ent, true);
CurEditor.TurnForcedPickOn();
CurEditor.PointMonitor += Editor_PointMonitor;
if (DynamicBlockAlignmentJig.Jig(ent))
tr.Commit();
CurEditor.PointMonitor -= Editor_PointMonitor;
CurEditor.TurnForcedPickOff();
}
}
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
CurEditor.WriteMessage(ex.Message);
}
#endregion
}
}