@GeeHaa wrote:
Hi
I'm looking to get the number of vertices in a polyline2d object. I see it for a regular polyline.Noofvertices object but not for polyline2d.
Thanks in Advance
While what follows might appear to be a case of swatting flies with a sledge hammer, it may prove useful in the future, depending on your needs.
Below are some of the extension methods that I use for dealing with 'complex' entities. Their purpose is to abstract away the complexity that results from their differing behavior, depending on if they are in a database or not. When complex entities are not in a database, they enumerate subentity objects. When they're in a database, they enumerate ObjectIds of subentity objects. This can make writing reusable code difficult because it must discriminate between complex entities that are/are-not database-resident. The extension methods allows those complex entity types to be dealt with uniformly and without regards for whether they are in a database or not.
To simply get the count of the vertices of any Polyline, Polyline2d, or Polyline3d, you can invoke the GetVertexCoordinates() extension method and pass the result to the Linq Count() method. The includeControlPoints argument indicates if control points should be included in the result, or not.
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
namespace Autodesk.AutoCAD.DatabaseServices
{
/// <summary>
/// Extension methods that support uniform ways to access subentities
/// of objects that expose them, abstracting away some of the complexity
/// resulting from differing behavior, depending on if the owner Entity
/// is datbase-resident or not.
///
/// All extension methods that accept an Entity that is the owner of
/// subentities will produce uniform results, regardless of whether the
/// owner entity is database-resident or not.
/// </summary>
public static class SubentityExensions
{
/// <summary>
/// Get the vertex world coordinates of a Polyline, Polyline2d, or Polyline3d
/// </summary>
/// <remarks>This method can be used on any Polyline, Polyline2d, or
/// Polyline3d, including those that are not Database-resident and
/// enumerate vertex entities rather than ObjectIds.
///
/// Control vertices can be excluded from the result if the
/// includeControlPoints argument is false</remarks>
/// <param name="polyline">A Polyline, Polyline2d, or Polyline3d</param>
/// <param name="trans">The transaction to use to open Vertex objects,
/// which is used only if the owner entity is database-resident.</param>
/// <param name="includingControlPoints">True to include control point
/// vertices of Polyline2d or Polyline3d</param>
/// <returns>An object that enumerates the polyline's vertex coordinates</returns>
public static IEnumerable<Point3d> GetVertexCoordinates(this Curve polyline, Transaction trans, bool includingControlPoints = false)
{
Assert.IsNotNull(polyline, "polyline");
Polyline pline = polyline as Polyline;
if(pline != null)
return Enumerable.Range(0, pline.NumberOfVertices).Select(i => pline.GetPoint3dAt(i));
Polyline2d pline2d = polyline as Polyline2d;
if(pline2d != null)
return pline2d.GetVertices(trans)
.Where(v => includingControlPoints || v.VertexType != Vertex2dType.SplineControlVertex)
.Select(v => pline2d.VertexPosition(v));
Polyline3d pline3d = polyline as Polyline3d;
if(pline3d != null)
return pline3d.GetVertices(trans)
.Where(v => includingControlPoints || v.VertexType != Vertex3dType.ControlVertex)
.Select(v => v.Position);
ErrorStatus.WrongObjectType.Check(false);
return null;
}
/// <summary>
/// Enumerates the vertices of a database-resident or memory-resident Polyine2d.
/// </summary>
/// <remarks>This method will enumerate the vertices of any Polyline2d, including
/// those that are not database-resident.
///
/// Its purpose is to abstract away the complexity imposed by the fact that different
/// types are enumerated by a Polyline2d, depending on if the polyline is database-
/// resident or not.
///
/// If a Polyline2d is database-resident, it will enumerate the ObjectIds of the
/// polyline's database-resident vertices. If a Polyline2d is not database-resident,
/// it will enumerate Vertex2d objects that are also not database-resident.</remarks>
/// <param name="polyline">The Polyline2d whose vertices are to be retrieved</param>
/// <param name="mode">The OpenMode used for opening database-resident Vertex2d objects</param>
/// <param name="trans">The Transaction to use to open database-resident Vertex2d objects.
/// If this argument is not supplied, the method will attempt to use the Top Transaction
/// of the database containing the polyline, or will raise an exception if there is no
/// Top transaction.
/// <returns>An object that enumerates the polyline's vertices</returns>
public static IEnumerable<Vertex2d> GetVertices(this Polyline2d polyline, OpenMode mode = OpenMode.ForRead, Transaction trans = null)
{
Assert.IsNotNull(polyline, "polyline");
return GetSubEntities<Vertex2d>(polyline, mode, trans);
}
public static IEnumerable<Vertex2d> GetVertices(this Polyline2d polyline, Transaction trans = null)
{
Assert.IsNotNull(polyline, "polyline");
return GetSubEntities<Vertex2d>(polyline, OpenMode.ForRead, trans);
}
/// <summary>
/// Same as above, except for use with Polyline3d/PolylineVertex3d
/// </summary>
public static IEnumerable<PolylineVertex3d> GetVertices(this Polyline3d polyline, OpenMode mode = OpenMode.ForRead, Transaction trans = null)
{
Assert.IsNotNull(polyline, "polyline");
return GetSubEntities<PolylineVertex3d>(polyline, mode, trans);
}
public static IEnumerable<PolylineVertex3d> GetVertices(this Polyline3d polyline, Transaction trans = null)
{
Assert.IsNotNull(polyline, "polyline");
return GetSubEntities<PolylineVertex3d>(polyline, OpenMode.ForRead, trans);
}
/// <summary>
/// Same as above, except for use with PolygonMesh/PolygonMeshVertex
/// </summary>
public static IEnumerable<PolygonMeshVertex> GetVertices(this PolygonMesh mesh, OpenMode mode = OpenMode.ForRead, Transaction trans = null)
{
Assert.IsNotNull(mesh, "mesh");
return GetSubEntities<PolygonMeshVertex>(mesh, mode, trans);
}
public static IEnumerable<PolygonMeshVertex> GetVertices(this PolygonMesh mesh, Transaction trans = null)
{
Assert.IsNotNull(mesh, "mesh");
return GetSubEntities<PolygonMeshVertex>(mesh, OpenMode.ForRead, trans);
}
/// <summary>
/// Same as above, except for use with PolyFaceMesh/PolyFaceMeshVertex
/// </summary>
public static IEnumerable<PolyFaceMeshVertex> GetVertices(this PolyFaceMesh mesh, OpenMode mode = OpenMode.ForRead, Transaction trans = null)
{
Assert.IsNotNull(mesh, "mesh");
return GetSubEntities<PolyFaceMeshVertex>(mesh, mode, trans);
}
public static IEnumerable<PolyFaceMeshVertex> GetVertices(this PolyFaceMesh mesh, Transaction trans = null)
{
Assert.IsNotNull(mesh, "mesh");
return GetSubEntities<PolyFaceMeshVertex>(mesh, OpenMode.ForRead, trans);
}
/// <summary>
/// Enumerates the AttributeReference objects owned by a given BlockReference
/// </summary>
/// <remarks>This method will uniformly enumerate the AttributeReference objects
/// of a BlockReference, including those that are not database-resident.
///
/// Its purpose is to abstract away the inherint complexity resulting from the
/// fact that different kinds of objects are contained in a BlockReference's
/// AttributeCollection, depending on if the BlockReference is database-resident,
/// or not.
///
/// If a BlockReference is database-resident, its AttributeCollection contains
/// the ObjectIds of its AttributeReferences. If a BlockReference is not database-
/// resident, its AttributeCollection contains its AttributeReference objects,
/// that are also not database-resident.</remarks>
/// <param name="blockRef">The BlockReference whose attributes are to be obtained</param>
/// <param name="mode">The OpenMode used for opening database-resident AttributeReferences</param>
/// <param name="trans">The Transaction to be used to open database-resident
/// AttributeReferences. If this argument is not provided, the method will attempt
/// to use the top transaction in the database containing the BlockReference, and
/// will throw an exception if there is no top transaction</param>
/// <returns></returns>
public static IEnumerable<AttributeReference> GetAttributes(this BlockReference blockRef, OpenMode mode = OpenMode.ForRead, Transaction trans = null, bool forceOpenOnLockedLayer = false)
{
Assert.IsNotNull(blockRef, "blockRef");
return GetSubEntities<AttributeReference>(blockRef, mode, trans, blockRef.AttributeCollection, forceOpenOnLockedLayer);
}
public static IEnumerable<AttributeReference> GetAttributes(this BlockReference blockRef, Transaction trans = null)
{
Assert.IsNotNull(blockRef, "blockRef");
return GetSubEntities<AttributeReference>(blockRef, OpenMode.ForRead, trans, blockRef.AttributeCollection);
}
/// <summary>
/// Worker for GetAttributes() and all GetVertices() overloads
/// </summary>
public static IEnumerable<T> GetSubEntities<T>(this Entity owner, OpenMode mode = OpenMode.ForRead, Transaction trans = null, IEnumerable source = null, bool forceOpenOnLockedLayer = false) where T : Entity
{
Assert.IsNotNull(owner, "owner");
IEnumerable enumerable = source ?? owner as IEnumerable;
ErrorStatus.InvalidInput.Check(enumerable != null, "No IEnumerable");
if(owner.Database != null)
{
trans = trans ?? owner.Database.TransactionManager.TopTransaction;
ErrorStatus.NoActiveTransactions.Check(trans != null);
foreach(ObjectId id in enumerable)
yield return (T) trans.GetObject(id, mode, false, forceOpenOnLockedLayer);
}
else
{
foreach(T entity in enumerable)
yield return entity;
}
}
}
}
namespace Autodesk.AutoCAD.Runtime
{
using AcRx = Autodesk.AutoCAD.Runtime;
public static class RuntimeExtensions
{
public static void Check(this ErrorStatus es, bool condition, string msg = null)
{
if(!condition)
{
if(msg == null)
throw new AcRx.Exception(es);
else
throw new AcRx.Exception(es, msg);
}
}
}
}
namespace System.Diagnostics
{
public static class Assert
{
public static void IsNotNull<T>(T obj, string name = null) where T : class
{
if(obj == null)
throw new ArgumentNullException(name ?? "unspecified");
}
}
}