.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to determine whether an object is Array(Rectangular)?

7 REPLIES 7
SOLVED
Reply
Message 1 of 8
583408432
331 Views, 7 Replies

How to determine whether an object is Array(Rectangular)?

I use the following code:

editor.WriteMessage($"\nType: {ent.GetType().FullName}");

 

just return:

Type: Autodesk.AutoCAD.DatabaseServices.BlockReference

 

I'm trying to get the specific type, like below:

583408432_0-1702107295738.png

 

7 REPLIES 7
Message 2 of 8
kdub_nz
in reply to: 583408432

@583408432 ,

 

jeff hornsby posted some code in vb.net at the swamp in 2012.

I have converted it to C#

Parts of this may lead you in the direction you want to go.

 

using System;
using System.Collections.Generic;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;
using OpenMode = Autodesk.AutoCAD.DatabaseServices.OpenMode;

// translated from https://www.theswamp.org/index.php?topic=37921.msg464332#msg464332

[assembly: CommandClass(typeof(Class1))]
public partial class Class1
{
   [CommandMethod("ReplaceItems")]
   public void ReplaceItems()
   {
      Document doc = CadApp.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;

      CadApp.ShowAlertDialog("Replace items in Associative Array\n original code by JeffH @ theSwamp\n mod to C# by kdub_nz");

      var peo1 = new PromptEntityOptions(Environment.NewLine + "Select an Associative Array: ");
      PromptEntityResult per1 = ed.GetEntity(peo1);
      if (per1.Status != PromptStatus.OK)
      {
         return;
      }
      if (!AssocArray.IsAssociativeArray(per1.ObjectId))
      {
         ed.WriteMessage(Environment.NewLine + "Not an Associative Array, please try again...");
         return;
      }

      var fullSubentityPaths = new List<FullSubentityPath>();
      if (AcHelper.SelectNestedEntities(Environment.NewLine + "Select array items: ", ref fullSubentityPaths) != PromptStatus.OK)
      {
         return;
      }

      CadApp.ShowAlertDialog(fullSubentityPaths.Count.ToString());

      var peo2 = new PromptEntityOptions(Environment.NewLine + "Select entity for substitution: ");
      PromptEntityResult per2 = ed.GetEntity(peo2);
      if (per2.Status != PromptStatus.OK)
      {
         return;
      }
      PromptPointResult ppr = ed.GetPoint(Environment.NewLine + "Select base point: ");
      if (ppr.Status != PromptStatus.OK)
      {
         return;
      }
      try
      {
         using (Transaction tr = db.TransactionManager.StartTransaction())
         {
            AssocArray array = AssocArray.GetAssociativeArray(per1.ObjectId);
            ItemLocator[] ItemLocators = AssocArray.getItemLocators(fullSubentityPaths.ToArray());
            var substEntities = new ObjectIdCollection();
            substEntities.Add(per2.ObjectId);
            var basePoint = new VertexRef(ppr.Value);
            array.ReplaceItems(ItemLocators, substEntities, basePoint);
            AssocManager.EvaluateTopLevelNetwork(db, default, 0);
            tr.Commit();
         }
      }
      catch (Autodesk.AutoCAD.Runtime.Exception ex)
      {
         CadApp.ShowAlertDialog(ex.Message + ex.StackTrace);
      }
   }

   //------------------------------------
   public partial class AcHelper
   {
      public static PromptStatus SelectNestedEntities(string prompt, ref ObjectIdCollection ids, ref List<FullSubentityPath> mypaths)
      {
         Document doc = CadApp.DocumentManager.MdiActiveDocument;
         Database db = doc.Database;
         Editor ed = doc.Editor;
         using (Transaction tr = db.TransactionManager.StartTransaction())
         {
            ids = new ObjectIdCollection();
            var pathsList = new List<FullSubentityPath>();
            var pneo = new PromptNestedEntityOptions(prompt);
            pneo.AllowNone = true;
            // Loop until cancelled or completed
            while (true)
            {
               PromptNestedEntityResult rs = ed.GetNestedEntity(pneo);
               // Return whether the function was cancelled
               if (rs.Status != PromptStatus.OK)
               {
                  mypaths = pathsList; // '.ToArray()
                  UnhighlightSubEntities(mypaths.ToArray());
                  return rs.Status != PromptStatus.None ? rs.Status : PromptStatus.OK;
               }
               ids.Add(rs.ObjectId);
               var path = HighlightSubEntity(rs);
               if (path != FullSubentityPath.Null)
               {
                  pathsList.Add(path);
               }
            }
         }
      }


      public static PromptStatus SelectNestedEntities(string prompt, ref List<FullSubentityPath> mypaths)
      {
         var ids = new ObjectIdCollection();
         return SelectNestedEntities(prompt, ref ids, ref mypaths);
      }


      private static FullSubentityPath HighlightSubEntity(PromptNestedEntityResult rs)
      {
         // Extract relevant information from the prompt object
         ObjectId selId = rs.ObjectId;
         var objIds = new List<ObjectId>(rs.GetContainers());
         // Reverse the "containers" list
         objIds.Reverse();
         // Now append the selected entity
         objIds.Add(selId);
         // Retrieve the sub-entity path for this entity
         var subEnt = new SubentityId(SubentityType.Null, IntPtr.Zero);
         var path = new FullSubentityPath(objIds.ToArray(), subEnt);
         // Open the outermost container, relying on the open transaction...
         Entity ent = objIds[0].GetObject(OpenMode.ForRead) as Entity;
         // ... and highlight the nested entity
         if (ent is null)
         {
            return FullSubentityPath.Null;
         }
         ent.Highlight(path, false);
         // Return the sub-entity path for later unhighlighting
         return path;
      }


      private static void UnhighlightSubEntities(FullSubentityPath[] mypaths)
      {
         foreach (FullSubentityPath path in mypaths)
         {
            if (path == FullSubentityPath.Null)
            {
               continue;
            }
            ObjectId[] ids = path.GetObjectIds();
            Entity ent = ids[0].GetObject(OpenMode.ForRead) as Entity;
            if (ent is not null)
            {
               ent.Unhighlight(path, false);
            }
         }
      }
   }
}

 

 

Regards,

 

 


// Called Kerry in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect.

class keyThumper<T> : Lazy<T>;      another  Swamper

Message 3 of 8
_gile
in reply to: 583408432

Hi,

Here's a way to determine the type of associative array via the DXF data.

    public enum AssocArrayType { None, Rectangular, Path, Polar }

    public static class Extension
    {
        public static AssocArrayType GetAssocArrayType(BlockReference br)
        {
            if (AssocArray.IsAssociativeArray(br.ObjectId))
                return AssocArrayType.None;
            var dependencyId = AssocDependency.GetFirstDependencyOnObject(br);
            var dependency = (AssocDependency)dependencyId.GetObject(OpenMode.ForRead);
            var dxfData = dependency.OwningAction.EntGet().AsArray();
            if (dxfData.Any(tv => tv == new TypedValue(1, "AxesAngle")))
                return AssocArrayType.Rectangular;
            if (dxfData.Any(tv => tv == new TypedValue(1, "FillAngle")))
                return AssocArrayType.Polar;
            if (dxfData.Any(tv => tv == new TypedValue(1, "FillPath")))
                return AssocArrayType.Path;
            else
                return AssocArrayType.None;
        }

        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("acdb24.dll", CallingConvention = CallingConvention.Cdecl,
            EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")]
        private static extern ErrorStatus acdbGetAdsName(out AdsName ename, ObjectId id);

        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl,
            EntryPoint = "acdbEntGet")]
        private static extern System.IntPtr acdbEntGet(AdsName ename);

        /// <summary>
        /// Get the DXF definition data (like AutoLISP entget function).
        /// </summary>
        /// <param name="id">Instance to which the method applies.</param>
        /// <returns>The DXF data.</returns>
        /// <exception cref="Exception">Thrown in case of invalid objectId.</exception>
        public static ResultBuffer EntGet(this ObjectId id)
        {
            var errorStatus = acdbGetAdsName(out AdsName ename, id);
            if (errorStatus != ErrorStatus.OK)
                throw new Exception(errorStatus);
            var result = acdbEntGet(ename);
            if (result != System.IntPtr.Zero)
                return ResultBuffer.Create(result, true);
            return null;
        }
    }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 8
kdub_nz
in reply to: 583408432

And add these to the [message 2] Class1 class 

and have a play

 

 

   [CommandMethod("RectandPolarAssocArr")]
   public void RectandPolarAssocArr()
   {
      Document doc = CadApp.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;

      using (Transaction tr = db.TransactionManager.StartTransaction())
      {
         var rectArrayEntitiesIds = new ObjectIdCollection();
         var polarArrayEntitiesIds = new ObjectIdCollection();
         BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, 
            OpenMode.ForRead);

         BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], 
            OpenMode.ForWrite);
         var circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 5);

         modelSpace.AppendEntity(circle);
         tr.AddNewlyCreatedDBObject(circle, true);
         var line = new Line(Point3d.Origin, new Point3d(5, 0, 0));

         modelSpace.AppendEntity(line);
         tr.AddNewlyCreatedDBObject(line, true);
         rectArrayEntitiesIds.Add(circle.ObjectId);
         polarArrayEntitiesIds.Add(line.ObjectId);
         var rectParams = new AssocArrayRectangularParameters()
         {
            ColumnCount = 10,
            ColumnSpacing = 10,
            RowCount = 10,
            RowSpacing = 10,
            RowElevation = 0,
            LevelCount = 10,
            LevelSpacing = 10,
            XAxisDirection = Vector3d.XAxis,
            YAxisDirection = Vector3d.YAxis,
            BasePoint = new VertexRef(new Point3d(50, 50, 0))
         };
         AssocArray.CreateArray(rectArrayEntitiesIds, rectParams.BasePoint, rectParams);

         var polarParams = new AssocArrayPolarParameters()
         {
            FillAngle = 360,
            AngleBetweenItems = 10,
            ItemCount = 36,
            RowCount = 10,
            RowElevation = 10,
            RowSpacing = 10,
            Radius = 30,
            Direction = AssocArrayPolarParameters.ArcDirection.CounterClockwise,
            StartAngle = 0,
            RotateItems = true
         };
         AssocArray.CreateArray(polarArrayEntitiesIds, new VertexRef(new Point3d(100, 100, 0)), polarParams);

         tr.Commit();
      }
   }


   [CommandMethod("ModifyRectandPolarAssocArr")]
   public void ModifyRectandPolarAssocArr()
   {
      Document doc = CadApp.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;

      using (Transaction tr = db.TransactionManager.StartTransaction())
      {
         var peo = new PromptEntityOptions(Environment.NewLine + "Select a Array: ");
         PromptEntityResult per = ed.GetEntity(peo);
         if (per.Status != PromptStatus.OK)
         {
            return;
         }
         if (!AssocArray.IsAssociativeArray(per.ObjectId))
         {
            return;
         }
         AssocArray array = AssocArray.GetAssociativeArray(per.ObjectId);

         if (array.GetParameters() is AssocArrayPolarParameters)
         {
            AssocArrayPolarParameters arrayPolarParam = 
               (AssocArrayPolarParameters)array.GetParameters();
            arrayPolarParam.ItemCount = arrayPolarParam.ItemCount / 2;
            arrayPolarParam.RowCount = arrayPolarParam.RowCount / 2;
            arrayPolarParam.RowSpacing = arrayPolarParam.RowSpacing / 2;
            arrayPolarParam.Commit();
         }
         else if (array.GetParameters() is AssocArrayRectangularParameters)
         {
            AssocArrayRectangularParameters arrayRecParam = 
               (AssocArrayRectangularParameters)array.GetParameters();
            arrayRecParam.ColumnCount = arrayRecParam.ColumnCount / 2;
            arrayRecParam.RowCount = arrayRecParam.RowCount / 2;
            arrayRecParam.RowSpacing = arrayRecParam.RowSpacing / 2;
            arrayRecParam.Commit();
         }
         else
         {
            return;
         }
         tr.Commit();
      }
   }

 


// Called Kerry in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect.

class keyThumper<T> : Lazy<T>;      another  Swamper

Message 5 of 8
_gile
in reply to: kdub_nz

@kdub_nz Nice! AssocArrayParameters is the way I was looking for and didn't find.

 

So, "to determine whether an object is Array(Rectangular)", we could simply do:

private static bool IsAssociativeRectangularArray(ObjectId id) =>
    AssocArray.IsAssociativeArray(id) &&
    AssocArray.GetAssociativeArray(id).GetParameters() is AssocArrayRectangularParameters;

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 6 of 8
kdub_nz
in reply to: 583408432

@_gile,

Yes Gilles, 

I think there is enough there to lead to a variety of solutions.
Jeff did some great  original research which gives us lots of options.

 

If it had been c# instead of vb.net it would have gotten more attention, and that's a pity !

 


// Called Kerry in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect.

class keyThumper<T> : Lazy<T>;      another  Swamper

Message 7 of 8
583408432
in reply to: _gile

Thanks for the answer! Very elegant solution, exactly what I was looking for. The only downside is that it only works with NET40+, it won't work in lower versions of AutoCAD.

Message 8 of 8

The only reason it won't work in the version of .net/C# that you're using is because that language version does not support expression-bodied members, which is what @_gile 's code uses.

 

It's a simple matter to rewrite it so that it will work on the version of C# that you are using. Just replace '=> <expr>;' with '{return <expr>;}'.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost