Author Topic: Associative Framework  (Read 4837 times)

0 Members and 1 Guest are viewing this topic.

Jeff H

  • Needs a day job
  • Posts: 6150
Associative Framework
« on: May 27, 2011, 03:08:51 AM »
For the love of God this took longer than I expected so i will post what I have.

Seems like I have seen this asked about alot and not much on it.
I thought this was new in 2012 but apparently came out in 2011

Most of code and ideas are from Stephen Preston class taught at Autodesk University--------See link at top of code


If anyone wants more examples or better explanation please reply.

Took longer than expected so not as detailed as plan but a start.

I plan on adding code for creating AssocVaribles to create parameters, dimensional Constraints if anyone wants if not won't worry about it.

Normally code in C# but went other way and converted VB to C# but fixed errors that I caught and looked okay at a glance.

Some of the helper methods were to just thin out code and not well thought-out because took too long.
----- Some bad ideas For Example how the Helper functions never commit transaction and rely on caller to create and commit transaction

Here is VB and C# code comments in code

Code: [Select]
' 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''''''''''''''''''''''''''''''''''''''''''''

Imports System
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput

<Assembly: CommandClass(GetType(AssociativeFrameWorkVB.MyCommands))>

Namespace AssociativeFrameWorkVB


    Public Class MyCommands

        Dim rdn As Random
        Private doc As Document
        Private db As Database
        Private ed As Editor

        Public Sub New()
            ActiveDoc = Application.DocumentManager.MdiActiveDocument
            rdn = New Random()
        End Sub
        '''''Little Trick picked up from Kerry Brown  http://www.theswamp.org/index.php
        Private Property ActiveDoc() As Document
            Get
                Return doc
            End Get

            Set(ByVal value As Document)
                doc = value

                If doc = Nothing Then
                    db = Nothing
                    ed = Nothing
                Else
                    db = doc.Database
                    ed = doc.Editor
                End If
            End Set

        End Property
#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
#End Region
        ' 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 Sub HorizontalConstraintByEntity()

            Using trx As Transaction = db.TransactionManager.StartTransaction()

                ''Helper Function that creates entity and adds it to the database
                Dim line As Entity = CreateRandomEntity(CreateEntityType.Line)

                'Our constrained geometry will be the edge of the line
                Dim lineFSP As FullSubentityPath = GetFullSubentityPath(line, SubentityType.Edge) ''Helper Function

                Dim paths() As FullSubentityPath = {lineFSP}

                Dim constraintGroup As Assoc2dConstraintGroup = 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()
            End Using

        End Sub

        <CommandMethod("HorizontalConstraintByStartandEndPoint")> _
        Public Sub HorizontalConstraintByStartandEndPoint()

            Using trx As Transaction = db.TransactionManager.StartTransaction()

                Dim line As Entity = 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
                Dim subentityIdPE As AssocPersSubentityIdPE = GetSubEntIdProtocolExt(line)
                'Now we have the PE, we query the subentities

                'First we retrieve a list of all edges (a line has one edge)
                Dim subentityIds() As SubentityId = subentityIdPE.GetAllSubentities(line, SubentityType.Edge)

                ' The next three variables are passed By Reference to GetEdgeVertexSubentities() method
                Dim startPntSubEntId As SubentityId = SubentityId.Null
                Dim endPntSubEntId As SubentityId = SubentityId.Null
                Dim otherPntsSubEntId() As SubentityId = Nothing '' First element would be a lines mid-point

                'Now we retrieve the vertices associated with that edge.
                subentityIdPE.GetEdgeVertexSubentities(line, subentityIds(0), startPntSubEntId, endPntSubEntId, otherPntsSubEntId)

                'The PE returns a SubEntId. We want a Full SubentityPath
                Dim ids() As ObjectId = {line.ObjectId}

                Dim lineFullSubEntPath As FullSubentityPath = New FullSubentityPath(ids, subentityIds(0))
                Dim startFullSubEntPath As FullSubentityPath = New FullSubentityPath(ids, startPntSubEntId)
                Dim endFullSubEntPath As FullSubentityPath = New FullSubentityPath(ids, endPntSubEntId)

                Dim constraintGroup As Assoc2dConstraintGroup = GetConstraintGroup(OpenMode.ForWrite)
                'Pass in geometry to constrain (the line edge)
                constraintGroup.AddConstrainedGeometry(lineFullSubEntPath)

                Dim paths() As FullSubentityPath = {startFullSubEntPath, endFullSubEntPath}

                constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Horizontal, paths)

                trx.Commit()
            End Using
        End Sub
        <CommandMethod("VerticalConstraintByEntity")> _
        Public Sub VerticalConstraintByEntity()
            Using trx As Transaction = db.TransactionManager.StartTransaction()

                Dim line As Entity = CreateRandomEntity(CreateEntityType.Line)
                Dim lineFSP As FullSubentityPath = GetFullSubentityPath(line, SubentityType.Edge)
                Dim paths() As FullSubentityPath = {lineFSP}
                Dim constraintGroup As Assoc2dConstraintGroup = GetConstraintGroup(OpenMode.ForWrite) ''Heler Function

                constraintGroup.AddConstrainedGeometry(lineFSP)
                constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Vertical, paths)

                trx.Commit()

            End Using

        End Sub
        <CommandMethod("VerticalConstraintByStartandEndPoint")> _
        Public Sub VerticalConstraintByStartandEndPoint()


            Using trx As Transaction = db.TransactionManager.StartTransaction()

                Dim line As Entity = CreateRandomEntity(CreateEntityType.Line) ''Helper Function
                Dim subentityIdPE As AssocPersSubentityIdPE = GetSubEntIdProtocolExt(line)
                Dim subentityIds() As SubentityId = subentityIdPE.GetAllSubentities(line, SubentityType.Edge)

                Dim startPntSubEntId As SubentityId = SubentityId.Null
                Dim endPntSubEntId As SubentityId = SubentityId.Null
                Dim otherPntsSubEntId() As SubentityId = Nothing

                subentityIdPE.GetEdgeVertexSubentities(line, subentityIds(0), startPntSubEntId, endPntSubEntId, otherPntsSubEntId)

                Dim ids() As ObjectId = {line.ObjectId}

                Dim lineFullSubEntPath As FullSubentityPath = New FullSubentityPath(ids, subentityIds(0))
                Dim startFullSubEntPath As FullSubentityPath = New FullSubentityPath(ids, startPntSubEntId)
                Dim endFullSubEntPath As FullSubentityPath = New FullSubentityPath(ids, endPntSubEntId)

                Dim constraintGroup As Assoc2dConstraintGroup = GetConstraintGroup(OpenMode.ForWrite)
                Dim paths() As FullSubentityPath = {startFullSubEntPath, endFullSubEntPath}

                constraintGroup.AddConstrainedGeometry(lineFullSubEntPath)
                constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Vertical, paths)

                trx.Commit()
            End Using
        End Sub
        <CommandMethod("FixedConstraintByEntity")> _
        Public Sub FixedConstraintByEntity()

            Using trx As Transaction = db.TransactionManager.StartTransaction


                Dim entity As Entity = CreateRandomEntity(CreateEntityType.Line) ''Helper Function to create Line or Circle with Random Points


                Dim assocsubentityIdPE As AssocPersSubentityIdPE = GetSubEntIdProtocolExt(entity)

                Dim subentityIds As SubentityId() = assocsubentityIdPE.GetAllSubentities(entity, SubentityType.Edge)

                Dim startSubEntId As SubentityId = SubentityId.Null
                Dim endSubEntId As SubentityId = SubentityId.Null
                Dim otherSubEntId As SubentityId() = Nothing

                assocsubentityIdPE.GetEdgeVertexSubentities(entity, subentityIds(0), startSubEntId, endSubEntId, otherSubEntId)

                Dim ids As ObjectId() = {entity.ObjectId}

                Dim lineSubEntPath As New FullSubentityPath(ids, subentityIds(0)) 'The line edge

                Dim otherFullSubEntPath As New FullSubentityPath(ids, otherSubEntId(0)) 'The edge's midPoint.

                
                Dim constraintGroup As Assoc2dConstraintGroup = GetConstraintGroup(OpenMode.ForWrite)
                'Pass in geometry to constrain (the line edge)
                constraintGroup.AddConstrainedGeometry(lineSubEntPath)

                Dim paths() As FullSubentityPath = {otherFullSubEntPath}
                'Now create the constraint, a Fixed constraint applied to the line's mid-point.
                constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Fix, paths)

                trx.Commit()
            End Using
        End Sub

        <CommandMethod("ColinearConstraintByEntity")> _
        Public Sub ColinearConstraintByEntity()


            Using trx As Transaction = db.TransactionManager.StartTransaction()
                Dim line1 As Line = CreateRandomEntity(CreateEntityType.Line)
                Dim line2 As Line = CreateRandomEntity(CreateEntityType.Line)

                Dim line1FSPath As FullSubentityPath = GetFullSubentityPath(line1, SubentityType.Edge)
                Dim line2FSPath As FullSubentityPath = GetFullSubentityPath(line2, SubentityType.Edge)


                Dim constraintGroup As Assoc2dConstraintGroup = GetConstraintGroup(OpenMode.ForWrite)
                constraintGroup.AddConstrainedGeometry(line1FSPath)
                constraintGroup.AddConstrainedGeometry(line2FSPath)

                Dim paths() As FullSubentityPath = {line1FSPath, line2FSPath}
                constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Collinear, paths)

                trx.Commit()
            End Using
        End Sub
        <CommandMethod("SymmetryConstraintByEntity")> _
        Public Sub SymmetryConstraintByEntity()

            Using trx As Transaction = db.TransactionManager.StartTransaction()

                Dim circle1 As Entity = CreateRandomEntity(CreateEntityType.Circle)
                Dim circle2 As Entity = CreateRandomEntity(CreateEntityType.Circle)
                Dim line As Entity = CreateRandomEntity(CreateEntityType.Line)

                Dim circle1FSPath As FullSubentityPath = GetFullSubentityPath(circle1, SubentityType.Edge)
                Dim circle2FSPath As FullSubentityPath = GetFullSubentityPath(circle2, SubentityType.Edge)
                Dim lineFSPath As FullSubentityPath = GetFullSubentityPath(line, SubentityType.Edge)

                Dim constraintGroup As Assoc2dConstraintGroup = GetConstraintGroup(OpenMode.ForWrite)

                constraintGroup.AddConstrainedGeometry(circle1FSPath)
                constraintGroup.AddConstrainedGeometry(circle2FSPath)
                constraintGroup.AddConstrainedGeometry(lineFSPath)

                Dim paths() As FullSubentityPath = {circle1FSPath, circle2FSPath, lineFSPath}
                constraintGroup.AddGeometricalConstraint(GeometricalConstraint.ConstraintType.Symmetric, paths)

                trx.Commit()
            End Using
        End Sub



#End Region
      


    End Class

    Public Enum CreateEntityType
        Circle
        Line
    End Enum


End Namespace

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Associative Framework
« Reply #1 on: May 27, 2011, 03:10:58 AM »
C#

Code: [Select]
// 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
    }


}

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Associative Framework
« Reply #2 on: May 27, 2011, 03:14:59 AM »
VB helper methods
Code: [Select]
#Region "Helper Functions"

#Region "Associative Framework Helper Functions"
        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        ''''''''''''''''''''''''''''''''''''''''''''''''FullSubentityPath '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        ''                                                                                                                           ''
        ''     This .NET class wraps the AcDbFullSubentPath ObjectARX class. This class is used for uniquely identifying             ''
        ''     a subentity within a particular entity. An object of this class consists of array of object IDs and an                ''
        ''     SubentityId object. The subentity ID object contains the graphics system marker of the subentity and the              ''
        ''     type of the subentity (that is, edge, face, vertex). The object ID array contains a sequential list of the            ''
        ''     object IDs for all the objects that make up the "path" from the outermost entity (in Model or Paper space) down       ''
        ''     into the "main" entity that the subentity is a part of. If the subentity's "main" entity is directly owned by the     ''
        ''     Model Space or Paper Space BlockTableRecords then the object ID array will have only one entry--the object ID of the  ''
        ''     "main" entity itself. For example, an edge of an Solid3d that's within a block definition that's referenced by an     ''
        ''     BlockReference would result in an object ID array with two object IDs. The first would be the object ID of the        ''
        ''     BlockReference. The second would be the object ID of the Solid3d                                                      ''
        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

        Private Function GetFullSubentityPath(ByVal entity As Entity, ByVal subentityType As SubentityType) As FullSubentityPath
            ' Create Protocol extension to query subentities
            Dim subentityIdPE As AssocPersSubentityIdPE = GetSubEntIdProtocolExt(entity)
            ' Get list of Sub Entites and for a line has one edge
            Dim subentityIds() As SubentityId = subentityIdPE.GetAllSubentities(entity, subentityType)

            Dim ids() As ObjectId = {entity.ObjectId}

            Return New FullSubentityPath(ids, subentityIds(0))

        End Function



        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''
        ''''''''''''''''''''''''''''''''''''''''''''''''Protocol extension ''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''
        ''                                                                                                                           ''
        ''                                                                                                                           ''
        ''      Protocol extension is a mechanism for adding functionality to existing ObjectARX classes. This new                   ''
        ''      functionality is embodied in protocol extension classes associated with an existing ObjectARX class                  ''
        ''      at runtime. The association of an ObjectARX class with protocol extension classes is made by way of                  ''
        ''      the ObjectARX class descriptor object, as described in chapter 16, Deriving a Custom ObjectARX Class                 ''
        ''      The class descriptor object describes the class and includes an array of pointers to any objects that                ''
        ''      extend the functionality of that class. An ObjectARX class can have any number of protocol extensions                ''
        ''      associated with it.                                                                                                  ''
        ''                                                                                                                           ''
        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

        Private Function GetSubEntIdProtocolExt(ByVal ent As Entity) As AssocPersSubentityIdPE
            Dim assocsubentityIdPE As AssocPersSubentityIdPE
            Dim peCls As RXClass = AssocPersSubentityIdPE.GetClass(GetType(AssocPersSubentityIdPE))
            Dim ptrSubentityIdPE As IntPtr = ent.QueryX(peCls)
            ''
            assocsubentityIdPE = TryCast(AssocPersSubentityIdPE.Create(ptrSubentityIdPE, False), AssocPersSubentityIdPE)
            If assocsubentityIdPE Is Nothing Then
                System.Windows.MessageBox.Show("cannot get subentityIdPE")
                Return Nothing
            End If
            Return assocsubentityIdPE
        End Function



        Private Function GetConstraintGroup(ByVal openMode As OpenMode) As Assoc2dConstraintGroup

            Dim currentPlane As Plane = GetCurrentPlane() ''''Helper Function to calculate Current Plane

            Dim constraintGroup As Assoc2dConstraintGroup

            Using trx As Transaction = db.TransactionManager.TopTransaction
                Dim modelSpaceId As ObjectId = GetModelSpaceId() '''' Helper Function to get ModelSpace's ObjectID
                Dim assocNetwrkId As ObjectId = AssocNetwork.GetInstanceFromObject(modelSpaceId, True, True, "")
                Dim assocNetwrk As AssocNetwork = trx.GetObject(assocNetwrkId, openMode.ForRead)
                ' Iterate all actions in network to find Assoc2dConstraintGroups
                Dim actionIds As ObjectIdCollection = assocNetwrk.GetActions
                For Each actionId As ObjectId In actionIds
                    If actionId = ObjectId.Null Then
                        Continue For
                    End If
                    If actionId.ObjectClass.Name = "AcDbAssoc2dConstraintGroup" Then
                        constraintGroup = trx.GetObject(actionId, openMode.ForRead)
                        ' Is this the Assoc2dConstraintGroup for our plane of interest?
                        If constraintGroup.GetWorkPlane.IsCoplanarTo(currentPlane) Then
                            If openMode.ForWrite Then
                                constraintGroup.UpgradeOpen()
                            End If
                            Return constraintGroup
                        End If
                    End If
                Next
                ' If we get to here, a suitable contraint group doesn't exist, create a new one if that's what calling fn wanted.

                assocNetwrk.UpgradeOpen()
                ' If model extent is far far away from origin then we need to shift
                '  construction plane origin within the model extent.
                ' (Use Pextmin, PExtmax in paper space)
                Dim extmin As Point3d = db.Extmin
                Dim extmax As Point3d = db.Extmax
                If extmin.GetAsVector().Length > 100000000.0 Then
                    Dim originL As Point3d = extmin + (extmax - extmin) / 2.0
                    Dim result As PointOnSurface = currentPlane.GetClosestPointTo(originL)
                    currentPlane.[Set](result.GetPoint(), currentPlane.Normal)
                End If
                ' Create the new constraint group and add it to the associative network.
                constraintGroup = New Assoc2dConstraintGroup(currentPlane)
                Dim constraintGroupId As ObjectId = db.AddDBObject(constraintGroup)
                assocNetwrk.AddAction(constraintGroupId, True)

            End Using
            Return constraintGroup
        End Function


        Private Function GetCurrentPlane() As Plane
            ' Calculate the current plane on which new entities are added by the editor
            ' (A combination of UCS and ELEVATION sysvar).
            Dim ucsMatrix As Matrix3d = ed.CurrentUserCoordinateSystem
            Dim origin As Point3d = ucsMatrix.CoordinateSystem3d.Origin
            Dim xAxis As Vector3d = ucsMatrix.CoordinateSystem3d.Xaxis
            Dim yAxis As Vector3d = ucsMatrix.CoordinateSystem3d.Yaxis
            Dim zAxis As Vector3d = ucsMatrix.CoordinateSystem3d.Zaxis
            origin = origin + CDbl(Application.GetSystemVariable("ELEVATION")) * zAxis

            Return New Plane(origin, xAxis, yAxis)
        End Function
#End Region



#Region "Geometry and Model Space Helper Functions"
        Private Function GetModelSpaceId() As ObjectId
            Dim trx As Transaction

            If db.TransactionManager.NumberOfActiveTransactions > 0 Then
                trx = db.TransactionManager.TopTransaction
            Else
                trx = db.TransactionManager.StartTransaction()
            End If

            Using trx
                Return SymbolUtilityServices.GetBlockModelSpaceId(db)
            End Using


        End Function

        Private Function GetModelSpace(ByVal openMode As OpenMode) As BlockTableRecord
            Dim trx As Transaction

            If db.TransactionManager.NumberOfActiveTransactions > 0 Then
                trx = db.TransactionManager.TopTransaction
            Else
                trx = db.TransactionManager.StartTransaction()
            End If

            Using trx
                Return trx.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), openMode)
            End Using


        End Function


        Private Function CreateRandomEntity(ByVal entType As CreateEntityType) As Entity
            Dim trx As Transaction

            If db.TransactionManager.NumberOfActiveTransactions > 0 Then
                trx = db.TransactionManager.TopTransaction
            Else
                trx = db.TransactionManager.StartTransaction()
            End If

            Dim ent As Entity
            Using trx

                Dim x1 As Double = rdn.NextDouble() + rdn.Next(100)
                Dim y1 As Double = rdn.NextDouble() + rdn.Next(100)

                Dim x2 As Double = rdn.NextDouble() + rdn.Next(100)
                Dim y2 As Double = rdn.NextDouble() + rdn.Next(100)

                If entType = CreateEntityType.Line Then
                    Dim line As New Line(New Point3d(x1, y1, 0), New Point3d(x2, y2, 0))
                    ent = line
                Else
                    If x2 < 2 Then
                        x2 = x2 + 5
                    End If
                    Dim circle As New Circle(New Point3d(x1, y1, 0), Vector3d.ZAxis, x2)
                    ent = circle
                End If

                Dim modelSpace As BlockTableRecord = GetModelSpace(OpenMode.ForWrite)
                Dim objId As ObjectId = modelSpace.AppendEntity(ent)
                trx.AddNewlyCreatedDBObject(ent, True)

                Return ent

            End Using

        End Function
#End Region


#End Region

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Associative Framework
« Reply #3 on: May 27, 2011, 03:15:32 AM »
C# helper methods


Code: [Select]
[code]

        #region "Helper Functions"

        #region "Associative Framework Helper Functions"
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////FullSubentityPath////////////////////////////////////////////////////////////
        //                                                                                                                           //
        //     This .NET class wraps the AcDbFullSubentPath ObjectARX class. This class is used for uniquely identifying             //
        //     a subentity within a particular entity. An object of this class consists of array of object IDs and an                //
        //     SubentityId object. The subentity ID object contains the graphics system marker of the subentity and the              //
        //     type of the subentity (that is, edge, face, vertex). The object ID array contains a sequential list of the            //
        //     object IDs for all the objects that make up the "path" from the outermost entity (in Model or Paper space) down       //
        //     into the "main" entity that the subentity is a part of. If the subentity's "main" entity is directly owned by the     //
        //     Model Space or Paper Space BlockTableRecords then the object ID array will have only one entry--the object ID of the  //
        //     "main" entity itself. For example, an edge of an Solid3d that's within a block definition that's referenced by an     //
        //     BlockReference would result in an object ID array with two object IDs. The first would be the object ID of the        //
        //     BlockReference. The second would be the object ID of the Solid3d                                                      //
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private FullSubentityPath GetFullSubentityPath(Entity entity, SubentityType subentityType)
        {
            // Create Protocol extension to query subentities
            AssocPersSubentityIdPE subentityIdPE = GetSubEntIdProtocolExt(entity);
            // Get list of Sub Entites and for a line has one edge
            SubentityId[] subentityIds = subentityIdPE.GetAllSubentities(entity, subentityType);

            ObjectId[] ids = { entity.ObjectId };

            return new FullSubentityPath(ids, subentityIds[0]);

        }



        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////Protocol extension//////////////////////////////////////////////////////
        //                                                                                                                           //
        //                                                                                                                           //
        //      Protocol extension is a mechanism for adding functionality to existing ObjectARX classes. This new                   //
        //      functionality is embodied in protocol extension classes associated with an existing ObjectARX class                  //
        //      at runtime. The association of an ObjectARX class with protocol extension classes is made by way of                  //
        //      the ObjectARX class descriptor object, as described in chapter 16, Deriving a Custom ObjectARX Class                 //
        //      The class descriptor object describes the class and includes an array of pointers to any objects that                //
        //      extend the functionality of that class. An ObjectARX class can have any number of protocol extensions                //
        //      associated with it.                                                                                                  //
        //                                                                                                                           //
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private AssocPersSubentityIdPE GetSubEntIdProtocolExt(Entity ent)
        {
            AssocPersSubentityIdPE assocsubentityIdPE = default(AssocPersSubentityIdPE);
            RXClass peCls = AssocPersSubentityIdPE.GetClass(typeof(AssocPersSubentityIdPE));
            IntPtr ptrSubentityIdPE = ent.QueryX(peCls);
            //'
            assocsubentityIdPE = AssocPersSubentityIdPE.Create(ptrSubentityIdPE, false) as AssocPersSubentityIdPE;
            if (assocsubentityIdPE == null)
            {
                System.Windows.MessageBox.Show("cannot get subentityIdPE");
                return null;
            }
            return assocsubentityIdPE;
        }



        private Assoc2dConstraintGroup GetConstraintGroup(OpenMode openMode)
        {

            Plane currentPlane = GetCurrentPlane();
            ///'Helper Function to calculate Current Plane

            Assoc2dConstraintGroup constraintGroup = default(Assoc2dConstraintGroup);

            using (Transaction trx = db.TransactionManager.TopTransaction)
            {
                ObjectId modelSpaceId = GetModelSpaceId();
                ///' Helper Function to get ModelSpace's ObjectID
                ObjectId assocNetwrkId = AssocNetwork.GetInstanceFromObject(modelSpaceId, true, true, "");
                AssocNetwork assocNetwrk = (AssocNetwork)trx.GetObject(assocNetwrkId, OpenMode.ForRead);
                // Iterate all actions in network to find Assoc2dConstraintGroups
                ObjectIdCollection actionIds = assocNetwrk.GetActions;
                foreach (ObjectId actionId in actionIds)
                {
                    if (actionId == ObjectId.Null)
                    {
                        continue;
                    }
                    if (actionId.ObjectClass.Name == "AcDbAssoc2dConstraintGroup")
                    {
                        constraintGroup = (Assoc2dConstraintGroup)trx.GetObject(actionId, OpenMode.ForRead);
                        // Is this the Assoc2dConstraintGroup for our plane of interest?
                        if (constraintGroup.GetWorkPlane.IsCoplanarTo(currentPlane))
                        {
                            if (openMode == OpenMode.ForWrite)
                            {
                                constraintGroup.UpgradeOpen();
                            }
                            return constraintGroup;
                        }
                    }
                }
                // If we get to here, a suitable contraint group doesn't exist, create a new one if that's what calling fn wanted.

                assocNetwrk.UpgradeOpen();
                // If model extent is far far away from origin then we need to shift
                //  construction plane origin within the model extent.
                // (Use Pextmin, PExtmax in paper space)
                Point3d extmin = db.Extmin;
                Point3d extmax = db.Extmax;
                if (extmin.GetAsVector().Length > 100000000.0)
                {
                    Point3d originL = extmin + (extmax - extmin) / 2.0;
                    PointOnSurface result = currentPlane.GetClosestPointTo(originL);
                    currentPlane.Set(result.GetPoint(), currentPlane.Normal);
                }
                // Create the new constraint group and add it to the associative network.
                constraintGroup = new Assoc2dConstraintGroup(currentPlane);
                ObjectId constraintGroupId = db.AddDBObject(constraintGroup);
                assocNetwrk.AddAction(constraintGroupId, true);
 
            }
            return constraintGroup;
        }


        private Plane GetCurrentPlane()
        {
            // Calculate the current plane on which new entities are added by the editor
            // (A combination of UCS and ELEVATION sysvar).
            Matrix3d ucsMatrix = ed.CurrentUserCoordinateSystem;
            Point3d origin = ucsMatrix.CoordinateSystem3d.Origin;
            Vector3d xAxis = ucsMatrix.CoordinateSystem3d.Xaxis;
            Vector3d yAxis = ucsMatrix.CoordinateSystem3d.Yaxis;
            Vector3d zAxis = ucsMatrix.CoordinateSystem3d.Zaxis;
            origin = origin + Convert.ToDouble(Application.GetSystemVariable("ELEVATION")) * zAxis;

            return new Plane(origin, xAxis, yAxis);
        }
        #endregion



        #region "Geometry and Model Space Helper Functions"
        private ObjectId GetModelSpaceId()
        {
            Transaction trx = default(Transaction);

            if (db.TransactionManager.NumberOfActiveTransactions > 0)
            {
                trx = db.TransactionManager.TopTransaction;
            }
            else
            {
                trx = db.TransactionManager.StartTransaction();
            }

            using (trx)
            {
                return SymbolUtilityServices.GetBlockModelSpaceId(db);
            }


        }

        private BlockTableRecord GetModelSpace(OpenMode openMode)
        {
            Transaction trx = default(Transaction);

            if (db.TransactionManager.NumberOfActiveTransactions > 0)
            {
                trx = db.TransactionManager.TopTransaction;
            }
            else
            {
                trx = db.TransactionManager.StartTransaction();
            }

            using (trx)
            {
                return (BlockTableRecord)trx.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), openMode);
            }


        }


        private Entity CreateRandomEntity(CreateEntityType entType)
        {
            Transaction trx = default(Transaction);

            if (db.TransactionManager.NumberOfActiveTransactions > 0)
            {
                trx = db.TransactionManager.TopTransaction;
            }
            else
            {
                trx = db.TransactionManager.StartTransaction();
            }

            Entity ent = default(Entity);
            using (trx)
            {

                double x1 = rdn.NextDouble() + rdn.Next(100);
                double y1 = rdn.NextDouble() + rdn.Next(100);

                double x2 = rdn.NextDouble() + rdn.Next(100);
                double y2 = rdn.NextDouble() + rdn.Next(100);

                if (entType == CreateEntityType.Line)
                {
                    Line line = new Line(new Point3d(x1, y1, 0), new Point3d(x2, y2, 0));
                    ent = line;
                }
               
                else
                {
                    if (x2 < 2)
                    {
                        x2 = x2 + 5;
                    }
                    Circle circle = new Circle(new Point3d(x1, y1, 0), Vector3d.ZAxis, x2);
                    ent = circle;
                }

                BlockTableRecord modelSpace = GetModelSpace(OpenMode.ForWrite);
                ObjectId objId = modelSpace.AppendEntity(ent);
                trx.AddNewlyCreatedDBObject(ent, true);

                return ent;

            }

        }
        #endregion


        #endregion




[/code]

kaefer

  • Guest
Re: Associative Framework
« Reply #4 on: May 27, 2011, 10:18:55 AM »
Thanks for the codez!
Quote
Code: [Select]
           Transaction trx = default(Transaction);

            if (db.TransactionManager.NumberOfActiveTransactions > 0)
            {
                trx = db.TransactionManager.TopTransaction;
            }
            else
            {
                trx = db.TransactionManager.StartTransaction();
            }

            using (trx)
            {
                return (BlockTableRecord)trx.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), openMode);
            }

Aren't you disposing someone else's transactions here?

For reference, here's the F#...
Code: [Select]
// 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

// See http://www.theswamp.org/index.php?topic=38418.0

module AssociativeFrameWorkCS

open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime

type acApp = Autodesk.AutoCAD.ApplicationServices.Application

type CreateEntityType =
    | Circle = 0
    | Line = 1

type MyCommands() =
    let doc = acApp.DocumentManager.MdiActiveDocument
    let db = doc.Database
    let ed = doc.Editor
    let rnd = new System.Random()

    // Associative Framework Helper Functions

    member private me.GetFullSubentityPath(entity: Entity, subentityType: SubentityType) =
        // Create Protocol extension to query subentities
        let subentityIdPE : AssocPersSubentityIdPE = me.GetSubEntIdProtocolExt entity
        // Get list of Sub Entites and for a line has one edge
        let subentityIds = subentityIdPE.GetAllSubentities(entity, subentityType)

        let ids = [| entity.ObjectId |]

        new FullSubentityPath(ids, subentityIds.[0])
    
    member private __.GetSubEntIdProtocolExt(ent: Entity) =
        let peCls = AssocPersSubentityIdPE.GetClass(typeof<AssocPersSubentityIdPE>)
        let ptrSubentityIdPE = ent.QueryX peCls
        //
        match AssocPersSubentityIdPE.Create(ptrSubentityIdPE, false) with
        | :? AssocPersSubentityIdPE as assocsubentityIdPE -> assocsubentityIdPE
        | _ -> failwith "cannot get subentityIdPE"
    
    member private me.GetConstraintGroup(openMode: OpenMode) =

        let currentPlane : Plane = me.GetCurrentPlane()
        /// Helper Function to calculate Current Plane

        let trx = db.TransactionManager.TopTransaction
        let modelSpaceId = me.GetModelSpaceId()
        ///  Helper Function to get ModelSpace's ObjectID

        let assocNetwrkId = AssocNetwork.GetInstanceFromObject(modelSpaceId, true, true, "")
        let assocNetwrk = trx.GetObject(assocNetwrkId, OpenMode.ForRead) :?> AssocNetwork
        // Iterate all actions in network to find Assoc2dConstraintGroups
        assocNetwrk.GetActions
        |> Seq.cast<ObjectId>
        |> Seq.tryPick
            (fun actionId ->
                if actionId <> ObjectId.Null && actionId.ObjectClass.Name = "AcDbAssoc2dConstraintGroup" then
                    let constraintGroup = trx.GetObject(actionId, OpenMode.ForRead) :?> Assoc2dConstraintGroup
                    // Is this the Assoc2dConstraintGroup for our plane of interest?
                    if constraintGroup.GetWorkPlane.IsCoplanarTo currentPlane then
                        if openMode = OpenMode.ForWrite then
                            constraintGroup.UpgradeOpen()
                        Some constraintGroup
                    else None
                else None )
        |> function
        | Some constraintGroup -> constraintGroup
        // If we get to here, a suitable constraint group doesn't exist, create a new one if that's what calling fn wanted.
        | None ->
            assocNetwrk.UpgradeOpen()
            // If model extent is far far away from origin then we need to shift
            //  construction plane origin within the model extent.
            // (Use Pextmin, PExtmax in paper space)
            let extmin = db.Extmin
            let extmax = db.Extmax
            if extmin.GetAsVector().Length > 100000000.0 then
                let originL = extmin + (extmax - extmin) / 2.0
                let result = currentPlane.GetClosestPointTo originL
                currentPlane.Set(result.GetPoint(), currentPlane.Normal)
            
            // Create the new constraint group and add it to the associative network.
            let constraintGroup = new Assoc2dConstraintGroup(currentPlane)
            let constraintGroupId = db.AddDBObject constraintGroup
            assocNetwrk.AddAction(constraintGroupId, true)
            constraintGroup

    member private __.GetCurrentPlane() =
    
        // Calculate the current plane on which new entities are added by the editor
        // (A combination of UCS and ELEVATION sysvar).
        let ucsMatrix = ed.CurrentUserCoordinateSystem
        let origin = ucsMatrix.CoordinateSystem3d.Origin
        let xAxis = ucsMatrix.CoordinateSystem3d.Xaxis
        let yAxis = ucsMatrix.CoordinateSystem3d.Yaxis
        let zAxis = ucsMatrix.CoordinateSystem3d.Zaxis
        let origin = origin + System.Convert.ToDouble(acApp.GetSystemVariable("ELEVATION")) * zAxis

        new Plane(origin, xAxis, yAxis)

    // Geometry and Model Space Helper Functions

    member private __.GetModelSpaceId() =
        if db.TransactionManager.NumberOfActiveTransactions > 0 then
            let trx = db.TransactionManager.TopTransaction
            SymbolUtilityServices.GetBlockModelSpaceId db
        else
            use trx = db.TransactionManager.StartTransaction()
            SymbolUtilityServices.GetBlockModelSpaceId db

    member private __.GetModelSpace(openMode: OpenMode) =
        if db.TransactionManager.NumberOfActiveTransactions > 0 then
            let trx = db.TransactionManager.TopTransaction
            trx.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), openMode) :?> BlockTableRecord
        else
            use trx = db.TransactionManager.StartTransaction()
            trx.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), openMode) :?> BlockTableRecord

    member private me.CreateRandomEntity(entType : CreateEntityType) =
        
        let makeEnt(trx: Transaction) =
            let x1 = rnd.NextDouble() + float(rnd.Next(100))
            let y1 = rnd.NextDouble() + float(rnd.Next(100))

            let x2 = rnd.NextDouble() + float(rnd.Next(100))
            let y2 = rnd.NextDouble() + float(rnd.Next(100))

            let ent =
                if entType = CreateEntityType.Line then
                    let line = new Line(new Point3d(x1, y1, 0.), new Point3d(x2, y2, 0.))
                    line :> Entity
                else
                    let x2 = if x2 < 2. then x2 + 5. else x2
                    let circle = new Circle(new Point3d(x1, y1, 0.), Vector3d.ZAxis, x2)
                    circle :> Entity
            
            let modelSpace = me.GetModelSpace OpenMode.ForWrite
            modelSpace.AppendEntity ent |> ignore
            trx.AddNewlyCreatedDBObject(ent, true)

            ent

        if db.TransactionManager.NumberOfActiveTransactions > 0 then
            let trx = db.TransactionManager.TopTransaction
            makeEnt trx
        else
            use trx = db.TransactionManager.StartTransaction()
            makeEnt trx
    
    // Command methods...
    // 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">]
    member me.HorizontalConstraintByEntity() =
        use trx = db.TransactionManager.StartTransaction()
    
        // Helper Function that creates entity and adds it to the database
        let line = me.CreateRandomEntity CreateEntityType.Line

        //Our constrained geometry will be the edge of the line
        let lineFSP = me.GetFullSubentityPath(line, SubentityType.Edge)

        let constraintGroup = me.GetConstraintGroup OpenMode.ForWrite

        //Add the constrained geometry to which the geometrical constraint will be applied
        constraintGroup.AddConstrainedGeometry lineFSP |> ignore
        //Now add the geometrical constraint
        constraintGroup.AddGeometricalConstraint(
            GeometricalConstraint.ConstraintType.Horizontal,
            [| lineFSP |] )
        |> ignore

        trx.Commit()
            
    [<CommandMethod "HorizontalConstraintByStartandEndPoint">]
    member me.HorizontalConstraintByStartandEndPoint() =
        use trx = db.TransactionManager.StartTransaction()
        let line = me.CreateRandomEntity CreateEntityType.Line
        
        //To query the subentities of the line, we create and use a protocol extension (PE) provided by the associativity API
        let subentityIdPE = me.GetSubEntIdProtocolExt line
        //Now we have the PE, we query the subentities

        //First we retrieve a list of all edges (a line has one edge)
        let subentityIds = subentityIdPE.GetAllSubentities(line, SubentityType.Edge)

        // The next three variables are passed By Reference to GetEdgeVertexSubentities() method
        let mutable startPntSubEntId = SubentityId.Null
        let mutable endPntSubEntId = SubentityId.Null
        let mutable otherPntsSubEntId : SubentityId[] = null
        //  First element would be a lines mid-point

        //Now we retrieve the vertices associated with that edge.
        subentityIdPE.GetEdgeVertexSubentities(line, subentityIds.[0], &startPntSubEntId, &endPntSubEntId, &otherPntsSubEntId)

        //The PE returns a SubEntId. We want a Full SubentityPath
        let ids = [| line.ObjectId |]

        let lineFullSubEntPath = new FullSubentityPath(ids, subentityIds.[0])
        let startFullSubEntPath = new FullSubentityPath(ids, startPntSubEntId)
        let endFullSubEntPath = new FullSubentityPath(ids, endPntSubEntId)

        let constraintGroup = me.GetConstraintGroup OpenMode.ForWrite
        //Pass in geometry to constrain (the line edge)
        constraintGroup.AddConstrainedGeometry lineFullSubEntPath |> ignore

        constraintGroup.AddGeometricalConstraint(
            GeometricalConstraint.ConstraintType.Horizontal,
            [| startFullSubEntPath; endFullSubEntPath |] )
        |> ignore

        trx.Commit()
            
    [<CommandMethod "VerticalConstraintByEntity">]
    member me.VerticalConstraintByEntity() =
        use trx = db.TransactionManager.StartTransaction()
        let line = me.CreateRandomEntity CreateEntityType.Line
        
        let lineFSP = me.GetFullSubentityPath(line, SubentityType.Edge)
        
        let constraintGroup = me.GetConstraintGroup OpenMode.ForWrite
        
        constraintGroup.AddConstrainedGeometry lineFSP |> ignore
        constraintGroup.AddGeometricalConstraint(
            GeometricalConstraint.ConstraintType.Vertical,
            [| lineFSP |] )
        |> ignore

        trx.Commit()

    [<CommandMethod "VerticalConstraintByStartandEndPoint">]
    member me.VerticalConstraintByStartandEndPoint() =
        use trx = db.TransactionManager.StartTransaction()
        let line = me.CreateRandomEntity CreateEntityType.Line

        // Helper Function
        let subentityIdPE = me.GetSubEntIdProtocolExt line
        let subentityIds = subentityIdPE.GetAllSubentities(line, SubentityType.Edge)

        let mutable startPntSubEntId = SubentityId.Null
        let mutable endPntSubEntId = SubentityId.Null
        let mutable otherPntsSubEntId : SubentityId[] = null

        subentityIdPE.GetEdgeVertexSubentities(line, subentityIds.[0], &startPntSubEntId, &endPntSubEntId, &otherPntsSubEntId)

        let ids = [| line.ObjectId |]

        let lineFullSubEntPath = new FullSubentityPath(ids, subentityIds.[0])
        let startFullSubEntPath = new FullSubentityPath(ids, startPntSubEntId)
        let endFullSubEntPath = new FullSubentityPath(ids, endPntSubEntId)

        let constraintGroup = me.GetConstraintGroup OpenMode.ForWrite

        constraintGroup.AddConstrainedGeometry lineFullSubEntPath |> ignore
        constraintGroup.AddGeometricalConstraint(
            GeometricalConstraint.ConstraintType.Vertical,
            [| startFullSubEntPath; endFullSubEntPath |] )
        |> ignore

        trx.Commit()
            
    [<CommandMethod "FixedConstraintByEntity">]
    member me.FixedConstraintByEntity() =
        use trx = db.TransactionManager.StartTransaction()
        let entity = me.CreateRandomEntity CreateEntityType.Line
        // Helper Function to create Line or Circle with Random Points

        let assocsubentityIdPE = me.GetSubEntIdProtocolExt entity

        let subentityIds = assocsubentityIdPE.GetAllSubentities(entity, SubentityType.Edge)

        let mutable startSubEntId = SubentityId.Null
        let mutable endSubEntId = SubentityId.Null
        let mutable otherSubEntId : SubentityId[] = null

        assocsubentityIdPE.GetEdgeVertexSubentities(entity, subentityIds.[0], &startSubEntId, &endSubEntId, &otherSubEntId)

        let ids = [| entity.ObjectId |]

        let lineSubEntPath = new FullSubentityPath(ids, subentityIds.[0])
        //The line edge

        let otherFullSubEntPath = new FullSubentityPath(ids, otherSubEntId.[0])
        //The edge's midPoint.

        let constraintGroup = me.GetConstraintGroup OpenMode.ForWrite
        //Pass in geometry to constrain (the line edge)
        constraintGroup.AddConstrainedGeometry lineSubEntPath |> ignore

        //Now create the constraint, a Fixed constraint applied to the line's mid-point.
        constraintGroup.AddGeometricalConstraint(
            GeometricalConstraint.ConstraintType.Fix,
            [| otherFullSubEntPath |] )
        |> ignore

        trx.Commit()
            
    [<CommandMethod "ColinearConstraintByEntity">]
    member me.ColinearConstraintByEntity() =
        use trx = db.TransactionManager.StartTransaction()

        let line1 = me.CreateRandomEntity CreateEntityType.Line
        let line2 = me.CreateRandomEntity CreateEntityType.Line

        let line1FSPath = me.GetFullSubentityPath(line1, SubentityType.Edge)
        let line2FSPath = me.GetFullSubentityPath(line2, SubentityType.Edge)

        let constraintGroup = me.GetConstraintGroup OpenMode.ForWrite
        constraintGroup.AddConstrainedGeometry line1FSPath |> ignore
        constraintGroup.AddConstrainedGeometry line2FSPath |> ignore

        constraintGroup.AddGeometricalConstraint(
            GeometricalConstraint.ConstraintType.Collinear,
            [| line1FSPath; line2FSPath |] )
        |> ignore

        trx.Commit()

    [<CommandMethod "SymmetryConstraintByEntity">]
    member me.SymmetryConstraintByEntity() =
        use trx = db.TransactionManager.StartTransaction()

        let circle1 = me.CreateRandomEntity(CreateEntityType.Circle)
        let circle2 = me.CreateRandomEntity(CreateEntityType.Circle)
        let line = me.CreateRandomEntity(CreateEntityType.Line)

        let circle1FSPath = me.GetFullSubentityPath(circle1, SubentityType.Edge)
        let circle2FSPath = me.GetFullSubentityPath(circle2, SubentityType.Edge)
        let lineFSPath = me.GetFullSubentityPath(line, SubentityType.Edge)

        let constraintGroup = me.GetConstraintGroup OpenMode.ForWrite
        constraintGroup.AddConstrainedGeometry circle1FSPath |> ignore
        constraintGroup.AddConstrainedGeometry circle2FSPath |> ignore
        constraintGroup.AddConstrainedGeometry lineFSPath |> ignore

        constraintGroup.AddGeometricalConstraint(
            GeometricalConstraint.ConstraintType.Symmetric,
            [| circle1FSPath; circle2FSPath; lineFSPath |])
         |> ignore

        trx.Commit()

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Associative Framework
« Reply #5 on: May 27, 2011, 11:25:25 AM »
I was breaking it up to be able to look at the code at  a more general sense to help me learn the API.

I was creating the transactions in the command methods and the helper functions are only called from command methods
then commited at end of command method.
Code: [Select]
Command Function
Create Tranaction
Call Helper Functions
Commit Transaction
End Command Function

Helper Function
Use Top Transaction
End Helper Function


Quote
Aren't you disposing someone else's transactions here?

I was not thinking and once you ponited that out I read the documention and thought this might be why? Not Sure
Quote
Within the using block, the object is read-only and cannot be modified or reassigned
Link to quote above


kaefer

  • Guest
Re: Associative Framework
« Reply #6 on: May 27, 2011, 01:15:22 PM »
Quote
Within the using block, the object is read-only and cannot be modified or reassigned
Link to quote above

It woudn't preclude calling methods on it, including Dispose(); et voila, instant rollback, unless I'm seriously missing something.

Come to think of it, trx.Commit() wouldn't hurt, either.

Keep it coming!

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Associative Framework
« Reply #7 on: May 27, 2011, 01:19:32 PM »
Quote
Within the using block, the object is read-only and cannot be modified or reassigned
Link to quote above

It woudn't preclude calling methods on it, including Dispose(); et voila, instant rollback, unless I'm seriously missing something.

Come to think of it, trx.Commit() wouldn't hurt, either.

Keep it coming!

I commited in a helper method and it went boom at the commit in command method.

Would need to test more if caused by transaction or a entity in the using block.