// Link to where most of code and ideas stolen from http://au.autodesk.com/?nd=class&session_id=7451
// The link above was a class taught by Stephen Preston at AutoDesk University http://au.autodesk.com/
// Class ID: CP316-5
// Class Title: Creating Parametric and Geometric Constraints Using the AutoCAD® .NET API
// This is code is rearranged and modified from original Author Stephen Preston
// Link to Stephen Preston Profile http://au.autodesk.com/?nd=my_profile&account_id=116657
Quote from link above
///Quote///
Stephen has been a member of the Autodesk Developer Technical Services (DevTech) team since 2000,
supporting the AutoCAD® ObjectARX®, .NET and ActiveX APIs, and also AutoCAD OEM, and RealDWG™.
Currently, he manages the DevTech Americas team and serves as Workgroup Lead, working closely
with the AutoCAD engineering team on future improvements in the AutoCAD APIs. Stephen started his
career as a scientist, and has a Ph.D. in Atomic and Laser Physics from the University of Oxford.
///EndQuote
using System;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
// This line is not mandatory, but improves loading performances
[assembly: CommandClass(typeof(AssociativeFrameWorkCS.MyCommands))]
namespace AssociativeFrameWorkCS
{
public class MyCommands
{
Random rdn;
private Document doc;
private Database db;
private Editor ed;
public MyCommands()
{
ActiveDoc = Application.DocumentManager.MdiActiveDocument;
rdn = new Random();
}
///''Little Trick picked up from Kerry Brown http://www.theswamp.org/index.php
private Document ActiveDoc
{
get { return doc; }
set
{
doc = value;
if (doc == null)
{
db = null;
ed = null;
}
else
{
db = doc.Database;
ed = doc.Editor;
}
}
}
#region "Code from Au University"
//See link at top for full source code
//horizontal constraint
//<CommandMethod("TESTHORIZONTAL")> _
//Public Sub testHorizontalCommand()
// Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
// Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager = db.TransactionManager
// Using myT As Transaction = tm.StartTransaction()
// 'Add line to database
// Dim bt As BlockTable = DirectCast(myT.GetObject(db.BlockTableId, OpenMode.ForRead, False), BlockTable)
// Dim btr As BlockTableRecord = DirectCast(myT.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite, False), BlockTableRecord)
// Dim line As New Line(New Point3d(5, 5, 0), New Point3d(15, 15, 0))
// btr.AppendEntity(line)
// myT.AddNewlyCreatedDBObject(line, True)
// 'Our constrained geometry will be the edge of the line
// Dim subentPath As FullSubentityPath = GetFullSubentityPath(line, SubentityType.Edge)
// Dim consGrpId As ObjectId = GetConstraintGroup(True)
// Dim consGeom As ConstrainedGeometry = Nothing
// Using constGrp As Assoc2dConstraintGroup = DirectCast(myT.GetObject(consGrpId, OpenMode.ForWrite, False), Assoc2dConstraintGroup)
// 'Add the constrained geometry to which the geometrical constraint will be applied
// consGeom = constGrp.AddConstrainedGeometry(subentPath)
// Dim paths As FullSubentityPath() = New FullSubentityPath(0) {subentPath}
// 'Now add the geometrical constraint
// Dim newConstraint As GeometricalConstraint = constGrp.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Horizontal, paths)
// Dim constraintArray As New List(Of GeometricalConstraint)()
// constraintArray.Add(newConstraint)
// End Using
// myT.Commit()
// End Using
//End Sub
#endregion
// If you look at the code above and source code many of the methods for example member methods
// of the Assoc2dConstraintGroup have a return type, but I ommitted them since
// the return value is not used for any of the following code. My intentions were to thin out the code
// to help me learn the API. Might need to be added for more useful and examples
// Basiclly noticed 2 branches or forms of code depending on if the entity was being constrained or a subentity of the
// entity. For example using a line's edge or a point on the line.
// The next two examples show the two types that produce the same result.
// HorizontalConstraintByEntity() uses the line's edge for a horizontal constraint and
// HorizontalConstraintByStartandEndPoint() uses the start and end point of a line to apply a horizontal constraint
// Will add most comments in first 2 methods and helper functions since they do not vary much
// Please remember you will only need to enter the first 2 to 3 letters of methods then press tab 1 to 2 times
// instead of typing the whole name
[CommandMethod("HorizontalConstraintByEntity")]
public void HorizontalConstraintByEntity()
{
using (Transaction trx = db.TransactionManager.StartTransaction())
{
//'Helper Function that creates entity and adds it to the database
Entity line = CreateRandomEntity(CreateEntityType.Line);
//Our constrained geometry will be the edge of the line
FullSubentityPath lineFSP = GetFullSubentityPath(line, SubentityType.Edge);
//'Helper Function
FullSubentityPath[] paths = { lineFSP };
Assoc2dConstraintGroup constraintGroup = GetConstraintGroup(OpenMode.ForWrite);
//'Heler Function
//Add the constrained geometry to which the geometrical constraint will be applied
constraintGroup.AddConstrainedGeometry(lineFSP);
//Now add the geometrical constraint
constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Horizontal, paths);
trx.Commit();
}
}
[CommandMethod("HorizontalConstraintByStartandEndPoint")]
public void HorizontalConstraintByStartandEndPoint()
{
using (Transaction trx = db.TransactionManager.StartTransaction())
{
Entity line = CreateRandomEntity(CreateEntityType.Line);
//'Helper Function
//To query the subentities of the line, we create and use a protocol extension (PE) provided by the associativity API
AssocPersSubentityIdPE subentityIdPE = GetSubEntIdProtocolExt(line);
//Now we have the PE, we query the subentities
//First we retrieve a list of all edges (a line has one edge)
SubentityId[] subentityIds = subentityIdPE.GetAllSubentities(line, SubentityType.Edge);
// The next three variables are passed By Reference to GetEdgeVertexSubentities() method
SubentityId startPntSubEntId = SubentityId.Null;
SubentityId endPntSubEntId = SubentityId.Null;
SubentityId[] otherPntsSubEntId = null;
//' First element would be a lines mid-point
//Now we retrieve the vertices associated with that edge.
subentityIdPE.GetEdgeVertexSubentities(line, subentityIds[0], ref startPntSubEntId, ref endPntSubEntId, ref otherPntsSubEntId);
//The PE returns a SubEntId. We want a Full SubentityPath
ObjectId[] ids = { line.ObjectId };
FullSubentityPath lineFullSubEntPath = new FullSubentityPath(ids, subentityIds[0]);
FullSubentityPath startFullSubEntPath = new FullSubentityPath(ids, startPntSubEntId);
FullSubentityPath endFullSubEntPath = new FullSubentityPath(ids, endPntSubEntId);
Assoc2dConstraintGroup constraintGroup = GetConstraintGroup(OpenMode.ForWrite);
//Pass in geometry to constrain (the line edge)
constraintGroup.AddConstrainedGeometry(lineFullSubEntPath);
FullSubentityPath[] paths = {startFullSubEntPath, endFullSubEntPath};
constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Horizontal, paths);
trx.Commit();
}
}
[CommandMethod("VerticalConstraintByEntity")]
public void VerticalConstraintByEntity()
{
using (Transaction trx = db.TransactionManager.StartTransaction())
{
Entity line = CreateRandomEntity(CreateEntityType.Line);
FullSubentityPath lineFSP = GetFullSubentityPath(line, SubentityType.Edge);
FullSubentityPath[] paths = { lineFSP };
Assoc2dConstraintGroup constraintGroup = GetConstraintGroup(OpenMode.ForWrite);
//'Heler Function
constraintGroup.AddConstrainedGeometry(lineFSP);
constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Vertical, paths);
trx.Commit();
}
}
[CommandMethod("VerticalConstraintByStartandEndPoint")]
public void VerticalConstraintByStartandEndPoint()
{
using (Transaction trx = db.TransactionManager.StartTransaction())
{
Entity line = CreateRandomEntity(CreateEntityType.Line);
//'Helper Function
AssocPersSubentityIdPE subentityIdPE = GetSubEntIdProtocolExt(line);
SubentityId[] subentityIds = subentityIdPE.GetAllSubentities(line, SubentityType.Edge);
SubentityId startPntSubEntId = SubentityId.Null;
SubentityId endPntSubEntId = SubentityId.Null;
SubentityId[] otherPntsSubEntId = null;
subentityIdPE.GetEdgeVertexSubentities(line, subentityIds[0], ref startPntSubEntId, ref endPntSubEntId, ref otherPntsSubEntId);
ObjectId[] ids = { line.ObjectId };
FullSubentityPath lineFullSubEntPath = new FullSubentityPath(ids, subentityIds[0]);
FullSubentityPath startFullSubEntPath = new FullSubentityPath(ids, startPntSubEntId);
FullSubentityPath endFullSubEntPath = new FullSubentityPath(ids, endPntSubEntId);
Assoc2dConstraintGroup constraintGroup = GetConstraintGroup(OpenMode.ForWrite);
FullSubentityPath[] paths = {startFullSubEntPath, endFullSubEntPath};
constraintGroup.AddConstrainedGeometry(lineFullSubEntPath);
constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Vertical, paths);
trx.Commit();
}
}
[CommandMethod("FixedConstraintByEntity")]
public void FixedConstraintByEntity()
{
using (Transaction trx = db.TransactionManager.StartTransaction())
{
Entity entity = CreateRandomEntity(CreateEntityType.Line);
//'Helper Function to create Line or Circle with Random Points
AssocPersSubentityIdPE assocsubentityIdPE = GetSubEntIdProtocolExt(entity);
SubentityId[] subentityIds = assocsubentityIdPE.GetAllSubentities(entity, SubentityType.Edge);
SubentityId startSubEntId = SubentityId.Null;
SubentityId endSubEntId = SubentityId.Null;
SubentityId[] otherSubEntId = null;
assocsubentityIdPE.GetEdgeVertexSubentities(entity, subentityIds[0], ref startSubEntId, ref endSubEntId, ref otherSubEntId);
ObjectId[] ids = { entity.ObjectId };
FullSubentityPath lineSubEntPath = new FullSubentityPath(ids, subentityIds[0]);
//The line edge
FullSubentityPath otherFullSubEntPath = new FullSubentityPath(ids, otherSubEntId[0]);
//The edge's midPoint.
Assoc2dConstraintGroup constraintGroup = GetConstraintGroup(OpenMode.ForWrite);
//Pass in geometry to constrain (the line edge)
constraintGroup.AddConstrainedGeometry(lineSubEntPath);
FullSubentityPath[] paths = { otherFullSubEntPath };
//Now create the constraint, a Fixed constraint applied to the line's mid-point.
constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Fix, paths);
trx.Commit();
}
}
[CommandMethod("ColinearConstraintByEntity")]
public void ColinearConstraintByEntity()
{
using (Transaction trx = db.TransactionManager.StartTransaction())
{
Entity line1 = CreateRandomEntity(CreateEntityType.Line);
Entity line2 = CreateRandomEntity(CreateEntityType.Line);
FullSubentityPath line1FSPath = GetFullSubentityPath(line1, SubentityType.Edge);
FullSubentityPath line2FSPath = GetFullSubentityPath(line2, SubentityType.Edge);
Assoc2dConstraintGroup constraintGroup = GetConstraintGroup(OpenMode.ForWrite);
constraintGroup.AddConstrainedGeometry(line1FSPath);
constraintGroup.AddConstrainedGeometry(line2FSPath);
FullSubentityPath[] paths = {line1FSPath, line2FSPath};
constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Collinear, paths);
trx.Commit();
}
}
[CommandMethod("SymmetryConstraintByEntity")]
public void SymmetryConstraintByEntity()
{
using (Transaction trx = db.TransactionManager.StartTransaction())
{
Entity circle1 = CreateRandomEntity(CreateEntityType.Circle);
Entity circle2 = CreateRandomEntity(CreateEntityType.Circle);
Entity line = CreateRandomEntity(CreateEntityType.Line);
FullSubentityPath circle1FSPath = GetFullSubentityPath(circle1, SubentityType.Edge);
FullSubentityPath circle2FSPath = GetFullSubentityPath(circle2, SubentityType.Edge);
FullSubentityPath lineFSPath = GetFullSubentityPath(line, SubentityType.Edge);
Assoc2dConstraintGroup constraintGroup = GetConstraintGroup(OpenMode.ForWrite);
constraintGroup.AddConstrainedGeometry(circle1FSPath);
constraintGroup.AddConstrainedGeometry(circle2FSPath);
constraintGroup.AddConstrainedGeometry(lineFSPath);
FullSubentityPath[] paths = {circle1FSPath, circle2FSPath, lineFSPath};
constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Symmetric, paths);
trx.Commit();
}
}
#endregion
}
public enum CreateEntityType
{
Circle,
Line
}
}