Streatch Command code in C#.net to streatch multiple segements of closed polygon

Streatch Command code in C#.net to streatch multiple segements of closed polygon

kbharathy9
Participant Participant
997 Views
8 Replies
Message 1 of 9

Streatch Command code in C#.net to streatch multiple segements of closed polygon

kbharathy9
Participant
Participant

Hi,

I want to streatch multiple segments of closed polygon using C#.net as we can streatch with AutoCAD command.

0 Likes
Accepted solutions (1)
998 Views
8 Replies
Replies (8)
Message 2 of 9

b_karunakar75
Participant
Participant

I will check and let you know

0 Likes
Message 3 of 9

kbharathy9
Participant
Participant

Please condiser Jig while streatching the feature.

0 Likes
Message 4 of 9

_gile
Consultant
Consultant
Accepted solution

Hi,

 

Here's a PolylineStretchJig example (the 'indexes' parameter contains the polyline indexes to stretch).

 

class PolylineStretchJig : EntityJig
{
    Polyline _pline;
    Plane _plane;
    Dictionary<int, Point2d> _vertices;
    Point3d _basePoint, _dragPoint;

    public PolylineStretchJig(Polyline pline, Point3d basePoint, List<int> indexes) : base(pline)
    {
        _pline = pline;
        _plane = new Plane(Point3d.Origin, pline.Normal);
        _vertices = indexes.ToDictionary(i => i, i => pline.GetPoint2dAt(i));
        _basePoint = basePoint;
    }

    protected override SamplerStatus Sampler(JigPrompts prompts)
    {
        var jppo = new JigPromptPointOptions()
        {
            Message = "\nSpecify second point: ",
            BasePoint = _basePoint,
            UseBasePoint = true
        };
        var result = prompts.AcquirePoint(jppo);
        if (result.Value.IsEqualTo(_dragPoint))
            return SamplerStatus.NoChange;
        _dragPoint = result.Value;
        return SamplerStatus.OK;
    }

    protected override bool Update()
    {
        Vector2d vector = (_dragPoint - _basePoint).Convert2d(_plane);
        foreach (var vertex in _vertices)
        {
            _pline.SetPointAt(vertex.Key, vertex.Value + vector);
        }
        return true;
    }
}

 

A testing command (should work as expected when View == Top).

 

public void Test()
{
    var doc = Application.DocumentManager.MdiActiveDocument;
    var db = doc.Database;
    var ed = doc.Editor;

    var promptEntityOptions = new PromptEntityOptions("\nSelect Polyline to strech: ");
    promptEntityOptions.SetRejectMessage("\nSelected object is not a polyline.");
    promptEntityOptions.AddAllowedClass(typeof(Polyline), true);
    var promptEntityResult = ed.GetEntity(promptEntityOptions);
    if (promptEntityResult.Status != PromptStatus.OK)
        return;

    var promptPointResult = ed.GetPoint("\nSelect vertices to stretch: ");
    if (promptPointResult.Status != PromptStatus.OK)
        return;

    var promptCornerResult = ed.GetCorner("\nSpecify the opposite corner", promptPointResult.Value);
    if (promptCornerResult.Status != PromptStatus.OK)
        return;

    using (var tr = db.TransactionManager.StartTransaction())
    {
        var ucs = ed.CurrentUserCoordinateSystem;
        var extents = new Extents3d();
        extents.AddPoint(promptPointResult.Value);
        extents.AddPoint(promptCornerResult.Value);
        extents.TransformBy(ucs);

        var pline = (Polyline)tr.GetObject(promptEntityResult.ObjectId, OpenMode.ForWrite);
        var indexes = new List<int>();

        bool IsPointInside(Point3d pt) =>
            extents.MinPoint.X <= pt.X &&
            extents.MinPoint.Y <= pt.Y &&
            extents.MinPoint.Z <= pt.Z &&
            pt.X <= extents.MaxPoint.X &&
            pt.Y <= extents.MaxPoint.Y &&
            pt.Z <= extents.MaxPoint.Z;
        for (int i = 0; i < pline.NumberOfVertices; i++)
        {
            if (IsPointInside(pline.GetPoint3dAt(i)))
                indexes.Add(i);
        }
        if (indexes.Count == 0)
            return;

        promptPointResult = ed.GetPoint("\nSpecify base point: ");
        if (promptPointResult.Status != PromptStatus.OK)
            return;
        var basePoint = promptPointResult.Value.TransformBy(ucs);

        var jig = new PolylineStretchJig(pline, basePoint, indexes);
        var promptResult = ed.Drag(jig);
        if (promptResult.Status != PromptStatus.OK)
            return;
        tr.Commit();
    }
}

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 9

ActivistInvestor
Mentor
Mentor

Hi @_gile, aside from performance reasons with a large number of vertices, I can think of several other reasons why I would prefer using Entity.MoveStretchPointsAt() verses manually moving each vertex as per your example.

 

Those other reasons are related to hatching: associative dimensions; and more generally, involvement in any kind of associative network where other objects have a dependence on the polyline.

 

Also, with Entity.MoveStretchPointsAt(), the solution would stretch any Entity, rather than just polylines.

 

Here is your example, hastily refactored to work with any Entity (untested):

 

using System;
using System.Linq;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

/// <summary>
/// Gile's example, refactored to stretch
/// any type of Entity that can be stretched.
/// </summary>

namespace Examples
{

   class EntityStretchJig : EntityJig
   {
      Entity entity;
      IntegerCollection indices;
      Point3d basePoint;
      Point3d lastPoint;
      Point3d samplePoint;

      public EntityStretchJig(Entity entity, Point3d basePoint, IntegerCollection indexes) 
         : base(entity)
      {
         if(entity == null)
            throw new ArgumentNullException(nameof(entity));
         if(!entity.IsWriteEnabled)
            throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NotOpenForWrite);
         Point3dCollection stretchPoints = new Point3dCollection();
         entity.GetStretchPoints(stretchPoints);
         if(stretchPoints.Count == 0)
            throw new ArgumentException("Can't stretch the given entity");
         if(indices.Count > stretchPoints.Count)
            throw new ArgumentException("Invalid index array");
         if(indices.Cast<int>().Max() >= stretchPoints.Count)
            throw new IndexOutOfRangeException();
         this.entity = entity;
         this.indices = indexes;
         this.basePoint = basePoint;
         this.lastPoint = basePoint;
      }

      protected override SamplerStatus Sampler(JigPrompts prompts)
      {
         var jppo = new JigPromptPointOptions()
         {
            Message = "\nSpecify second point: ",
            BasePoint = basePoint,
            UseBasePoint = true
         };
         var result = prompts.AcquirePoint(jppo);
         if(result.Status != PromptStatus.OK)
            return SamplerStatus.Cancel;
         if(result.Value.IsEqualTo(lastPoint))
            return SamplerStatus.NoChange;
         samplePoint = result.Value;
         return SamplerStatus.OK;
      }

      protected override bool Update()
      {
         entity.MoveStretchPointsAt(indices, samplePoint - lastPoint);
         lastPoint = samplePoint;
         return true;
      }
   }


   public static class TestCase
   {
      [CommandMethod("MYSTRETCH")]
      public static void Test()
      {
         var doc = Application.DocumentManager.MdiActiveDocument;
         var db = doc.Database;
         var ed = doc.Editor;

         var peo = new PromptEntityOptions("\nSelect entity to strech: ");
         var per = ed.GetEntity(peo);
         if(per.Status != PromptStatus.OK)
            return;

         var ppr = ed.GetPoint("\nSelect vertices to stretch: ");
         if(ppr.Status != PromptStatus.OK)
            return;

         var pcr = ed.GetCorner("\nSpecify the opposite corner", ppr.Value);
         if(pcr.Status != PromptStatus.OK)
            return;

         var ucs = ed.CurrentUserCoordinateSystem;
         var extents = new Extents3d();
         extents.AddPoint(ppr.Value);
         extents.AddPoint(pcr.Value);
         extents.TransformBy(ucs);
         Point3dCollection stretchPoints = new Point3dCollection();
         using(var tr = db.TransactionManager.StartTransaction())
         {
            var entity = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForRead);
            entity.GetStretchPoints(stretchPoints);
            tr.Commit();
         }

         /// Let's try to avoid user interatiion inside an
         /// active transaction, to avoid undesired side-
         /// effects of aborting the transaction (e.g.,
         /// undoing transparent pans/zooms, etc.).
        
         if(stretchPoints.Count == 0)
         {
            ed.WriteMessage("\nCan't stretch selected entity.");
            return;
         }
         IntegerCollection list = new IntegerCollection(stretchPoints.Count);
         for(int i = 0; i < stretchPoints.Count; i++)
         {
            if(extents.Contains(stretchPoints[i]))
               list.Add(i);
         }
         if(list.Count == 0)
            return;
         ppr = ed.GetPoint("\nSpecify base point: ");
         if(ppr.Status != PromptStatus.OK)
            return;
         var basePoint = ppr.Value.TransformBy(ucs);
         using(var tr = db.TransactionManager.StartTransaction())
         {
            var entity = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
            var jig = new EntityStretchJig(entity, basePoint, list);
            var promptResult = ed.Drag(jig);
            if(promptResult.Status != PromptStatus.OK)
               return;
            tr.Commit();
         }
      }
   }

   public static class NoCopyAndPasteExtensions
   {
      public static bool Contains(this Extents3d extents, Point3d pt)
      {
         Point3d min = extents.MinPoint;
         Point3d max = extents.MaxPoint;
         return min.X <= pt.X && min.Y <= pt.Y && min.Z <= pt.Z 
            && pt.X <= max.X && pt.Y <= max.Y && pt.Z <= max.Z;
      }
   }
}

 

Message 6 of 9

_gile
Consultant
Consultant

@ActivistInvestor

I didn't know this method.

Thanks for make me (us) discover it and for the code sample.

There's a little mistake (typo?) in the EntityStretchJig constructor: 'indices' instead of 'indexes' lines 36 and 38.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 7 of 9

ActivistInvestor
Mentor
Mentor

Hi @_gile, thanks for pointing out that bug. The last thing I did before copying it was to move all the assignments to the bottom of the constructor, not realizing that was a mistake.

 

 

using System;
using System.Linq;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

/// <summary>
/// Gile's example, refactored to stretch
/// any type of Entity that can be stretched.
/// </summary>

namespace Examples
{

   class EntityStretchJig : EntityJig
   {
      Entity entity;
      IntegerCollection indices;
      Point3d basePoint;
      Point3d lastPoint;
      Point3d samplePoint;

      public EntityStretchJig(Entity entity, Point3d basePoint, IntegerCollection indexes) 
         : base(entity)
      {
         if(entity == null)
            throw new ArgumentNullException(nameof(entity));
         if(indexes == null)
            throw new ArgumentNullException(nameof(indexes));
         if(!entity.IsWriteEnabled)
            throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NotOpenForWrite);
         Point3dCollection stretchPoints = new Point3dCollection();
         entity.GetStretchPoints(stretchPoints);
         if(stretchPoints.Count == 0)
            throw new ArgumentException("Can't stretch the given entity");
         if(indexes.Count > stretchPoints.Count)
            throw new ArgumentException("Invalid index array");
         if(indexes.Cast<int>().Max() >= stretchPoints.Count)
            throw new IndexOutOfRangeException();
         this.indices = indexes;
         this.entity = entity;
         this.basePoint = basePoint;
         this.lastPoint = basePoint;
      }

      protected override SamplerStatus Sampler(JigPrompts prompts)
      {
         var jppo = new JigPromptPointOptions()
         {
            Message = "\nSpecify second point: ",
            BasePoint = basePoint,
            UseBasePoint = true
         };
         var result = prompts.AcquirePoint(jppo);
         if(result.Status != PromptStatus.OK)
            return SamplerStatus.Cancel;
         if(result.Value.IsEqualTo(lastPoint))
            return SamplerStatus.NoChange;
         samplePoint = result.Value;
         return SamplerStatus.OK;
      }

      protected override bool Update()
      {
         entity.MoveStretchPointsAt(indices, samplePoint - lastPoint);
         lastPoint = samplePoint;
         return true;
      }
   }


   public static class TestCase
   {
      [CommandMethod("MYSTRETCH")]
      public static void Test()
      {
         var doc = Application.DocumentManager.MdiActiveDocument;
         var db = doc.Database;
         var ed = doc.Editor;

         var peo = new PromptEntityOptions("\nSelect entity to strech: ");
         var per = ed.GetEntity(peo);
         if(per.Status != PromptStatus.OK)
            return;

         var ppr = ed.GetPoint("\nSelect vertices to stretch: ");
         if(ppr.Status != PromptStatus.OK)
            return;

         var pcr = ed.GetCorner("\nSpecify the opposite corner", ppr.Value);
         if(pcr.Status != PromptStatus.OK)
            return;

         var ucs = ed.CurrentUserCoordinateSystem;
         var extents = new Extents3d();
         extents.AddPoint(ppr.Value);
         extents.AddPoint(pcr.Value);
         extents.TransformBy(ucs);
         Point3dCollection stretchPoints = new Point3dCollection();
         using(var tr = db.TransactionManager.StartTransaction())
         {
            var entity = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForRead);
            entity.GetStretchPoints(stretchPoints);
            tr.Commit();
         }

         /// Try to avoid user interatiion inside an
         /// active transaction, to avoid undesired side-
         /// effects of aborting the transaction (e.g.,
         /// undoing transparent pans/zooms, etc.).
        
         if(stretchPoints.Count == 0)
         {
            ed.WriteMessage("\nCan't stretch selected entity.");
            return;
         }
         IntegerCollection list = new IntegerCollection(stretchPoints.Count);
         for(int i = 0; i < stretchPoints.Count; i++)
         {
            if(extents.Contains(stretchPoints[i]))
               list.Add(i);
         }
         if(list.Count == 0)
            return;
         ppr = ed.GetPoint("\nSpecify base point: ");
         if(ppr.Status != PromptStatus.OK)
            return;
         var basePoint = ppr.Value.TransformBy(ucs);
         using(var tr = db.TransactionManager.StartTransaction())
         {
            var entity = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
            var jig = new EntityStretchJig(entity, basePoint, list);
            var promptResult = ed.Drag(jig);
            if(promptResult.Status != PromptStatus.OK)
               return;
            tr.Commit();
         }
      }
   }

   public static class NoCopyAndPasteExtensions
   {
      public static bool Contains(this Extents3d extents, Point3d pt)
      {
         Point3d min = extents.MinPoint;
         Point3d max = extents.MaxPoint;
         return min.X <= pt.X && min.Y <= pt.Y && min.Z <= pt.Z 
            && pt.X <= max.X && pt.Y <= max.Y && pt.Z <= max.Z;
      }
   }
}

 

Message 8 of 9

kbharathy9
Participant
Participant

Thank you @_gile . The code you shared is working fine for me.

0 Likes
Message 9 of 9

_gile
Consultant
Consultant

@kbharathy9

The code shared by @ActivistInvestor (message #7) is more robust. You should use it instead.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes