Author Topic: Draw rectangles at regular interval on Polyline, Badly need in help...  (Read 9864 times)

0 Members and 1 Guest are viewing this topic.

sachinpise

  • Guest
Hello...

Sorry to post similar topic again but didn't want my question to be confusing.
I want to add rectangles on regular interval on polyline. I am able to get 2 vertices that are on the selected polyline, thanks to the forum. But not able to draw remaining 2 vertices to form the rectangle.

Here is my code:


Code: [Select]
[CommandMethod("VT")]
        static public void test()
        {
            var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;
            var db = HostApplicationServices.WorkingDatabase;
            const double space = 200.0;
            var length = 400.0;
            var width = 50.0;
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var result = ed.GetEntity("Select a polyline:");
                if (result.Status != PromptStatus.OK)
                    return;
                var pline = (Polyline)tr.GetObject(result.ObjectId, OpenMode.ForRead);
                var pt1 = pline.GetPoint3dAt(0);
                var pt2 = pline.GetPoint3dAt(1);
                var vec3D = (Vector3d)(pt2 - pt1);

                var wpDistance = pt1.DistanceTo(pt2);

                var spacingVector = vec3D.MultiplyBy(space / wpDistance);

                var steps = (int)(wpDistance / space);
                var pointList = new Point3dCollection();
                for (var i = 1; i <= steps; i++)
                {
                    var nextPoint = pt1.Add(spacingVector.MultiplyBy(i));
                    pointList.Add(nextPoint);
                }
                steps = (int)(wpDistance / width);
                var sizeVector = vec3D.MultiplyBy(width / wpDistance);
                var pointList2 = new List<Point3d>();
                for (var i = 1; i <= steps; i++)
                {
                    var nextPoint = pt1.Add(sizeVector.MultiplyBy(i));
                    pointList2.Add(nextPoint);
                }
                for (var i = 0; i < pointList.Count; i++)
                {
                    var pt = pointList[i];
                    var index = pointList2.IndexOf(pointList2.FirstOrDefault(x => x == pt));
                    var endPt = pointList2[index + 1];
                    var polyline = new Polyline();
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(pt.X, pt.Y), 0, 0, 0);
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(endPt.X, endPt.Y), 0, 0, 0);

                    //I NEED TO ADD NEXT TWO VERTICES WITH 400 LENGTH TO FORM RECTANGLE ON THE EDGE OF SELECTED POLYLINE.

                    BlockManager.AddEntity(polyline);
                }
                tr.Commit();
            }
        }

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #1 on: December 20, 2010, 01:09:41 AM »
Sachin Pise

Your use of var does not make it easy for anyone who is going to try to help you.

It makes an attempt to get a feel for intent very difficult ..

//------

var pointList2 = new List<Point3d>();
declares a System.Collections.Generic.List<Autodesk.AutoCAD.Geometry.Point3d>
is this your intent ??

because  
var index = pointList2.IndexOf(pointList2.FirstOrDefault(x => x == pt));

will throw an error ... FirstOrDefault is a method an IDictionary

//------
What is Blockmanager ??

BlockManager.AddEntity(polyline);

//-------
Is it your design assumption that the UCS is WORLD ??

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

sachinpise

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #2 on: December 20, 2010, 01:29:51 AM »
Hi Kerry

I am sorry for that. Here is a same code with Type explicit.

Code: [Select]
static public void test()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = HostApplicationServices.WorkingDatabase;
            const double space = 200.0;
            double length = 400.0;
            double width = 50.0;
            using(var tr = db.TransactionManager.StartTransaction())
            {
                PromptEntityResult result = ed.GetEntity("Select a polyline:");
                if (result.Status != PromptStatus.OK)
                    return;
                Polyline pline = (Polyline) tr.GetObject(result.ObjectId, OpenMode.ForRead);
                Point3d pt1 = pline.GetPoint3dAt(0);
                Point3d pt2 = pline.GetPoint3dAt(1);
                Vector3d vec3D = (Vector3d) (pt2 - pt1);

                double wpDistance = pt1.DistanceTo(pt2);

                Vector3d spacingVector = vec3D.MultiplyBy(space / wpDistance);

                int steps = (int) (wpDistance / space);
                Point3dCollection pointList = new Point3dCollection();
                for(int i = 1; i <= steps; i++)
                {
                    Point3d nextPoint = pt1.Add(spacingVector.MultiplyBy(i));
                    pointList.Add(nextPoint);
                }
                steps = (int) (wpDistance / width);
                Vector3d sizeVector = vec3D.MultiplyBy(width / wpDistance);
                List<Point3d> pointList2 = new List<Point3d>();
                for(int i = 1; i <= steps; i++)
                {
                    Point3d nextPoint = pt1.Add(sizeVector.MultiplyBy(i));
                    pointList2.Add(nextPoint);
                }
                for(int i = 0; i < pointList.Count; i++)
                {
                    Point3d pt = pointList[i];
                    int index = pointList2.IndexOf(pointList2.FirstOrDefault(x => x == pt));
                    Point3d endPt = pointList2[index + 1];
                    Polyline polyline = new Polyline();
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(pt.X, pt.Y), 0, 0, 0);
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(endPt.X, endPt.Y), 0, 0, 0);

                    //I NEED TO ADD NEXT TWO VERTICES WITH 400 LENGTH TO FORM RECTANGLE ON THE EDGE OF SELECTED POLYLINE.

                    BlockManager.AddEntity(polyline);
                }
                tr.Commit();
            }
        }


Sachin Pise

Your use of var does not make it easy for anyone who is going to try to help you.

It makes an attempt to get a feel for intent very difficult ..

//------

var pointList2 = new List<Point3d>();
declares a System.Collections.Generic.List<Autodesk.AutoCAD.Geometry.Point3d>
is this your intent ??

because  
var index = pointList2.IndexOf(pointList2.FirstOrDefault(x => x == pt));

will throw an error ... FirstOrDefault is a method an IDictionary

//------
What is Blockmanager ??

BlockManager.AddEntity(polyline);

//-------
Is it your design assumption that the UCS is WORLD ??



sachinpise

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #3 on: December 20, 2010, 01:33:52 AM »
Hi Kerry

FirstOrDefault is LINQ.

This question "Is it your design assumption that the UCS is WORLD ??" is bouncing for me.

BlockManager is a class I wrote to which has some reusable methods. Here is my BlockManager class.

Code: [Select]
public static class BlockManager
    {
        #region BlockType enum
        public enum BlockType
        {
            ModelSpace = 0,
            PaperSpace = 1,
        }
        #endregion
        public static ObjectId AddEntity(Entity entity)
        {
            var idEntity = AddEntity(entity, BlockType.ModelSpace);
            return idEntity;
        }
        public static ObjectId AddEntity(Entity entity, BlockType blockType)
        {
            ObjectId entityId;
            var db = HostApplicationServices.WorkingDatabase;
            using(var trans = db.TransactionManager.StartTransaction())
            {
                var bt = (BlockTable) (trans.GetObject(db.BlockTableId, OpenMode.ForWrite));
                BlockTableRecord blockTableRecord = null;
                switch(blockType)
                {
                    case BlockType.ModelSpace:
                        blockTableRecord =
                                (BlockTableRecord) trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                        break;
                    case BlockType.PaperSpace:
                        blockTableRecord =
                                (BlockTableRecord) trans.GetObject(bt[BlockTableRecord.PaperSpace], OpenMode.ForWrite);
                        break;
                }
                blockTableRecord.AppendEntity(entity);
                trans.AddNewlyCreatedDBObject(entity, true);
                entityId = entity.ObjectId;
                trans.Commit();
            }
            return entityId;
        }
}


Sachin Pise

Your use of var does not make it easy for anyone who is going to try to help you.

It makes an attempt to get a feel for intent very difficult ..

//------

var pointList2 = new List<Point3d>();
declares a System.Collections.Generic.List<Autodesk.AutoCAD.Geometry.Point3d>
is this your intent ??

because  
var index = pointList2.IndexOf(pointList2.FirstOrDefault(x => x == pt));

will throw an error ... FirstOrDefault is a method an IDictionary

//------
What is Blockmanager ??

BlockManager.AddEntity(polyline);

//-------
Is it your design assumption that the UCS is WORLD ??



Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #4 on: December 20, 2010, 02:23:59 AM »
Quote
FirstOrDefault is LINQ.

Yes, I worked that out  :)

Thanks for posting the updated code.

I'm going out for a couple of hours ... I may be able to have a look tonight, otherwise tomorrow.

//-----

It appears from a quick read that you are trying to add another polyline rather than edit the original pline .. is that correct ?
also seems  that you expect the selected polyline to have vertex 0 at the left end of the selected segment ... is this your design intent ?
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

sachinpise

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #5 on: December 20, 2010, 03:25:43 AM »
Hi Kerry... Thanks a lot for looking at it. Basically my output should as seen in the attached image.

To answer your questions:

It appears from a quick read that you are trying to add another polyline rather than edit the original pline .. is that correct ?
Yes. On the selected base polyline, I want to add number of rectangles. (please see the image)

Also seems  that you expect the selected polyline to have vertex 0 at the left end of the selected segment ... is this your design intent ?
All the new rectangle polylines will be either on left or right of the selected segment. Basically I made my overall issue to look simple so, the selected segment (Polyline) is only with 2 vertices looking like simple line with two points. But actually it is going to be a box (4 vertices closed Polyline). And depending on the side user selects and with the midpoint of the box I determine weather the newly created rectangle polylines will be on left or right.

Quote
FirstOrDefault is LINQ.

Yes, I worked that out  :)

Thanks for posting the updated code.

I'm going out for a couple of hours ... I may be able to have a look tonight, otherwise tomorrow.

//-----

It appears from a quick read that you are trying to add another polyline rather than edit the original pline .. is that correct ?
also seems  that you expect the selected polyline to have vertex 0 at the left end of the selected segment ... is this your design intent ?


kaefer

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #6 on: December 20, 2010, 10:00:56 AM »
Code: [Select]
                    Point3d pt = pointList[i];
                    int index = pointList2.IndexOf(pointList2.FirstOrDefault(x => x == pt));
                    Point3d endPt = pointList2[index + 1];

Wouldn't List<T>.FindIndex do?

Quote
Code: [Select]
                    //I NEED TO ADD NEXT TWO VERTICES WITH 400 LENGTH TO FORM RECTANGLE ON THE EDGE OF SELECTED POLYLINE.

Now it is in order to practice a little vector algebra. You're asking for the points 400 units perpendicular to the points your already have. You could get the angle and do the polar thing, or try this instead:

Code: [Select]
            let v = (endPt - pt).GetPerpendicularVector().MultiplyBy length
            let p1 = pt + v
            let p2 = endPt + v

Cheers

sachinpise

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #7 on: December 20, 2010, 01:08:50 PM »
Hi Kaefer

Thanks for the suggestions. It works like charm. I also tried drawing base segment in every angle and it works fine. Now one question though, for drawing the rectangles on left side I use (-length) and to draw on right side I use (length) and it is working fine. But I hope technically I am doing it right.

Also you said "You could get the angle and do the polar thing", but I hope this way it is alright. Please once see the attached code:

Code: [Select]
[CommandMethod("VT")]
        public static void test()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = HostApplicationServices.WorkingDatabase;
            const double space = 200.0;
            double length = 400.0;
            double width = 50.0;
            using (var tr = db.TransactionManager.StartTransaction())
            {
                PromptEntityResult result = ed.GetEntity("Select a polyline:");
                if (result.Status != PromptStatus.OK)
                    return;
                var pline = (Polyline)tr.GetObject(result.ObjectId, OpenMode.ForRead);
                Point3d pt1 = pline.GetPoint3dAt(0);
                Point3d pt2 = pline.GetPoint3dAt(1);
                Vector3d vec3D = (Vector3d)(pt2 - pt1);
                double wpDistance = pt1.DistanceTo(pt2);
                Vector3d spacingVector = vec3D.MultiplyBy(space / wpDistance);
                int steps = (int)(wpDistance / space);
                Point3dCollection pointList = new Point3dCollection();
                for (int i = 1; i <= steps; i++)
                {
                    Point3d nextPoint = pt1.Add(spacingVector.MultiplyBy(i));
                    pointList.Add(nextPoint);
                }

                for (int i = 0; i < pointList.Count; i++)
                {
                    Point3d startPt = pointList[i];
                    Vector3d vector = vec3D.DivideBy(vec3D.Length);
                    vector = vector.MultiplyBy(width);
                    Point3d endPt = startPt + vector;
                    vector = (endPt - startPt).GetPerpendicularVector().MultiplyBy(-length);
                    Point3d startPt1 = startPt + vector;
                    Point3d endPt1 = endPt + vector;
                    Polyline polyline = new Polyline();
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(startPt.X, startPt.Y), 0, 0, 0);
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(endPt.X, endPt.Y), 0, 0, 0);
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(endPt1.X, endPt1.Y), 0, 0, 0);
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(startPt1.X, startPt1.Y), 0, 0, 0);
                    polyline.Closed = true;
                    BlockManager.AddEntity(polyline);
                }
                tr.Commit();
            }
        }

Regards,
Sachin

Code: [Select]
                   Point3d pt = pointList[i];
                    int index = pointList2.IndexOf(pointList2.FirstOrDefault(x => x == pt));
                    Point3d endPt = pointList2[index + 1];

Wouldn't List<T>.FindIndex do?

Quote
Code: [Select]
                   //I NEED TO ADD NEXT TWO VERTICES WITH 400 LENGTH TO FORM RECTANGLE ON THE EDGE OF SELECTED POLYLINE.

Now it is in order to practice a little vector algebra. You're asking for the points 400 units perpendicular to the points your already have. You could get the angle and do the polar thing, or try this instead:

Code: [Select]
           let v = (endPt - pt).GetPerpendicularVector().MultiplyBy length
            let p1 = pt + v
            let p2 = endPt + v

Cheers

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #8 on: December 21, 2010, 04:36:26 AM »


appears that you have your problem sorted Sachin.
My holiday activity is interfering with writing code but I'll attempt to find the time to finish the alternative I started.

Regarding the UCS question :
Do you do all (or most of) your work in World UCS ( or planar with world ie rotated around world Z) ?

It affects how much translation from current UCS to World needs to be done.

Regards
Kerry

This the sort of thing you had in mind ??
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

sachinpise

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #9 on: December 21, 2010, 05:18:00 AM »
Hi Kerry

What you showing in GIF is exactly what I was looking for. Also, like you said, I have sorted it out using Kaefer's help. But I dont know what is your approach and if you are not very busy then would like to know how you managed it.

Regarding UCS question, I just searched on internet about UCS and AutoCAD and found it is to deploy the 3D system in AutoCAD. So my answer would be that I use default USC or World UCS, because my application is 2D.

Regards,
Sachin Pise



appears that you have your problem sorted Sachin.
My holiday activity is interfering with writing code but I'll attempt to find the time to finish the alternative I started.

Regarding the UCS question :
Do you do all (or most of) your work in World UCS ( or planar with world ie rotated around world Z) ?

It affects how much translation from current UCS to World needs to be done.

Regards
Kerry

This the sort of thing you had in mind ??

« Last Edit: December 21, 2010, 05:31:03 AM by Sachin »

kaefer

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #10 on: December 21, 2010, 06:47:08 AM »
Regarding the UCS question :
Do you do all (or most of) your work in World UCS ( or planar with world ie rotated around world Z) ?

It affects how much translation from current UCS to World needs to be done.

Hi Kerry,

that' a tricky little question. On the one hand there's no user input of coordinates involved, on the other the orientation of the resultant little boxes relative to the Polyline needs to be defined in terms of an XY-plane or Z-normal, which might as well come from the current UCS.

To avoid overcomplicating the issue, I'd like to show an alternative approach ignoring the current UCS, which stems from the fact that we're basically duplicating the ARRAY command here. A template rectangle in a kind of virtual UCS is constructed, then transformed into WCS and subsequently cloned as often as needed.

Code: [Select]
[<CommandMethod "TestV1">]
let testV1() =
    let ed = acApp.DocumentManager.MdiActiveDocument.Editor
    let db = HostApplicationServices.WorkingDatabase

    let space = 200.0
    let length = 400.0
    let width = 50.0

    let peo = new PromptEntityOptions("Select a Polyline:")
    peo.SetRejectMessage("Not a Polyline.")
    peo.AddAllowedClass(typeof<Polyline>, false)
    let per = ed.GetEntity peo
    if per.Status = PromptStatus.OK then

        use tr = db.TransactionManager.StartTransaction()
        let inPline = tr.GetObject(per.ObjectId, OpenMode.ForRead) :?> Polyline
        let btr =
            tr.GetObject(inPline.OwnerId, OpenMode.ForWrite)
                :?> BlockTableRecord
       
        let pt0 = inPline.GetPoint3dAt 0
        let pt1 = inPline.GetPoint3dAt 1
        let len = pt0.DistanceTo pt1
        let spacingVector = (pt1 - pt0).MultiplyBy(space / len)
        let steps = len / space |> int
       
        // Create rectangle in UCS
        use rectangle = new Polyline(4, Closed = true)
        rectangle.AddVertexAt(0, new Point2d(0., 0.), 0., 0., 0.)
        rectangle.AddVertexAt(1, new Point2d(0., width), 0., 0., 0.)
        rectangle.AddVertexAt(2, new Point2d(length, width), 0., 0., 0.)
        rectangle.AddVertexAt(3, new Point2d(length, 0.), 0., 0., 0.)

        // For equal end spacing, determine distance from pt0 to new origin
        // of rectangle
        let rest = len - (space * float steps)
        let offset = space - 0.5 * (space - width + rest)

        // Transform the rectangle as template for cloning
        let recOrigin = pt0 - spacingVector.MultiplyBy(offset / space)
        let recYAxis = spacingVector.GetNormal()
        let recXAxis = recYAxis.GetPerpendicularVector().GetNormal()
        let recZAxis = (recYAxis.CrossProduct recXAxis).GetNormal()
        Matrix3d.AlignCoordinateSystem(
            Point3d.Origin,
            Vector3d.XAxis,
            Vector3d.YAxis,
            Vector3d.ZAxis,
            recOrigin,
            recXAxis,
            recYAxis,
            recZAxis )
        |> rectangle.TransformBy

        // Clone the rectangle /steps/ times along /spacingVector/
        let clone (dbo: Entity) _ =
            let clone = dbo.Clone() :?> Entity
            clone.TransformBy (Matrix3d.Displacement spacingVector)
            btr.AppendEntity clone |> ignore
            tr.AddNewlyCreatedDBObject(clone, true)
            clone
   
        List.fold clone (rectangle :> Entity) [1 .. steps] |> ignore
   
        tr.Commit()

For pictorial reference I refer to my honourable friend's animated illustration.

All the best

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #11 on: December 21, 2010, 07:21:18 AM »
kaefer;

Thats essentially what I have done .. create one rectangle and array it in one Axis, so there are no Lists of points involved. .

I've rationalised the location of the first rectangle so that the open distance either end of the line segment is the same.
I've also done some mojo with the selection of the line segment and determining the vertex points.

Now that I know we don't need to make allowance for 3d and any UCS, I'll clean it up tomorrow and post the code.

//-----

Sachin,
I imagine these are core holes for concrete panels, yes ??


kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

sachinpise

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #12 on: December 21, 2010, 08:28:29 AM »
Hi Kerrry

These are not core holes, but these are hacking for Hollowcore slabs. Hacking is required for additional reinforcement, so the slabs are hacked at these location with the dimensions provided.

Thanks & Regards,
Sachin

kaefer;

Thats essentially what I have done .. create one rectangle and array it in one Axis, so there are no Lists of points involved. .

I've rationalised the location of the first rectangle so that the open distance either end of the line segment is the same.
I've also done some mojo with the selection of the line segment and determining the vertex points.

Now that I know we don't need to make allowance for 3d and any UCS, I'll clean it up tomorrow and post the code.

//-----

Sachin,
I imagine these are core holes for concrete panels, yes ??




sachinpise

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #13 on: December 21, 2010, 11:35:40 AM »
One more issue with what was working for me so far... From whatever I tried to do with both your help, I am not able to figure out how to apply the rectangles on left or right side of the polyline. I know whether it should be left of right, but can't manage with (-length) or (+length)

Regards,
Sachin

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #14 on: December 21, 2010, 06:44:31 PM »
Sachin

I currently have it working so that the direction is controlled by the nearest end of the line you select
ie: If you select the left end the rectangles are under
select the right for over
or a better way to think about it ; look along the line from the end nearest the selection and the rectangles will draw on the right.

I'm not really happy with that though and had thought to add a user selection (mouse-click) for the side to draw on.
also, it may be best to provide an over-ride for the distance to the first slot ... a simple prompt with enter (mouse-click) to confirm.

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.