Author Topic: Draw rectangles at regular interval on Polyline, Badly need in help...  (Read 9866 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.

sachinpise

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #15 on: December 22, 2010, 12:28:51 AM »
Hello Kerry, Kaefer

I am really stuck with following code. I have a method which tells me weather the rectangles should be drawn on left side or right side. But I am not able to get the left/ right direction correct. Please see the following code, I am sure I have messed it out...


Code: [Select]
for (int i = 0; i < pointList.Count; i++)
                {
                    Point3d point1 = pointList[i];
                    Vector3d vector = vec3D.DivideBy(vec3D.Length);
                    vector = vector.MultiplyBy(width);
                    Point3d point2 = point1 + vector;
                    vector = drawOnLeft.Value ? (point1 - point2).GetPerpendicularVector().MultiplyBy(length) : (point2 - point1).GetPerpendicularVector().MultiplyBy(length);
                    Point3d point3 = point2 + vector;
                    Point3d point4 = point1 + vector;
                    if (!PolylineManager.PointInsidePoly(point3, slabPolyline.ObjectId))
                        continue;
                    if (!PolylineManager.PointInsidePoly(point4, slabPolyline.ObjectId))
                        continue;
                    Autodesk.AutoCAD.DatabaseServices.Polyline polyline = new Autodesk.AutoCAD.DatabaseServices.Polyline();
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(point1.X, point1.Y), 0, 0, 0);
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(point2.X, point2.Y), 0, 0, 0);
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(point3.X, point3.Y), 0, 0, 0);
                    polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(point4.X, point4.Y), 0, 0, 0);
                    polyline.Closed = true;
                    polylineList.Add(polyline);
                }

I tried both following ways with no expected result.


Code: [Select]
vector = drawOnLeft.Value ? (point1 - point2).GetPerpendicularVector().MultiplyBy(length) : (point2 - point1).GetPerpendicularVector().MultiplyBy(length);


Code: [Select]
vector = (point2 - point1).GetPerpendicularVector().MultiplyBy(drawOnLeft.Value ? length : -length);


kaefer

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #16 on: December 22, 2010, 06:59:12 AM »


I can't really understand why you would have trouble with this. You aren't telling us the whole truth, perhaps?

Quote
Code: [Select]
vector = drawOnLeft.Value ? (point1 - point2).GetPerpendicularVector().MultiplyBy(length) : (point2 - point1).GetPerpendicularVector().MultiplyBy(length);

Code: [Select]
vector = (point2 - point1).GetPerpendicularVector().MultiplyBy(drawOnLeft.Value ? length : -length);

These two look pretty equivalent. If you'd like yet another way to come to the very same result, see the definition of PolarPoint e.g. here http://www.theswamp.org/index.php?topic=31861.msg386487#msg386487. Determine the angle of point2 - point1 and call PolarPoint with PI / 2. added to the angle.

That should not be surprising given the operation of Vector3d.GetPerpendicularVector(), which returns a normalized new Vector(-y, x, z) .

Cheers
« Last Edit: December 22, 2010, 09:25:04 AM by kaefer »

sachinpise

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #17 on: December 22, 2010, 08:53:38 AM »
Hi Kaefer

No luck in understanding what you meant... I tried some options with big exceptions.

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 #18 on: December 22, 2010, 09:36:03 AM »

How about s0mething like this. ??

Code to follow.
The code needs some pruning, but it's past my bedtime.
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.

kaefer

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #19 on: December 22, 2010, 09:48:02 AM »
No luck in understanding what you meant... I tried some options with big exceptions.

See, the side your little boxes are on is dependent on the order of your two base points, i.e the direction of your polyline. Now, in the absence of any corrective action this will be the left hand side of your polyline, as if you'd have rotated them by 90 degrees counterclockwise.

You seem to apply that correction by means of your drawOnLeft.Value, so any possible error must have occured before that. That's why I'm unable to see anything untoward with your code fragment.

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 #20 on: December 22, 2010, 09:57:03 AM »

Code: [Select]

// (C) CodeHimBelonga kdub@theSwamp 2010
//
using System;
using System.Windows.Forms;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(kdub_Testing.LittleBoxes))]

namespace kdub_Testing
{
    public class LittleBoxes
    {
        Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
        Database db = HostApplicationServices.WorkingDatabase;

        [CommandMethod("HACK3")]
        public void HACK3()
        {
            double spacing = 200.0;
            double length = 400.0;
            double width = 50.0;
            Point3d ptStart = new Point3d();
            Point3d ptEnd = new Point3d();

            //-1 if ptSide is on left side
            //+1 if ptSide is on right side
            int hackSide = 0;

            bool proceed = GetUserInput(ref ptStart, ref ptEnd, ref hackSide);

            if(proceed == false) {
                System.Windows.Forms.MessageBox.Show("You Made Boo-Boo Selection",
                    "Oooops",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation
                    );
                return;
            }
            Vector3d v1 = (Vector3d)(ptEnd - ptStart);
            double wpLen = v1.Length;

            int spacingCount = (int)((wpLen / spacing) - 2);
            Vector3d spacingVector = v1.MultiplyBy(spacing / wpLen);
            Vector3d firstVec = v1.MultiplyBy(((wpLen - (spacingCount * spacing) - width) / 2) / wpLen);

            // draw first box
            // describe the PolyLine rectangle corners as vectors relative to the firstCorner
            //
            Vector3d xLen = v1.DivideBy(v1.Length).MultiplyBy(width);
            Vector3d yLen = v1.GetPerpendicularVector().MultiplyBy(-(hackSide * length));
            Point3d vertex0 = ptStart.Add(firstVec);
            Point3d vertex1 = vertex0 + yLen;
            Point3d vertex2 = vertex1 + xLen;
            Point3d vertex3 = vertex0 + xLen;


            using(Transaction tr = db.TransactionManager.StartTransaction()) {
                Polyline polyline = new Polyline();
                polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(vertex0.X, vertex0.Y), 0, 0, 0);
                polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(vertex1.X, vertex1.Y), 0, 0, 0);
                polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(vertex2.X, vertex2.Y), 0, 0, 0);
                polyline.AddVertexAt(polyline.NumberOfVertices, new Point2d(vertex3.X, vertex3.Y), 0, 0, 0);
                polyline.Closed = true;

                ObjectId plRectangle = ExtensionTools.AddToCurrentSpaceAndClose(polyline, db);
                ExtensionTools.ArrayInAxis(plRectangle, db, (spacingCount + 1), spacingVector);
                tr.Commit();
            }
        }
    }
}

Code: [Select]
        public bool GetUserInput(ref Point3d ptStart, ref Point3d ptEnd, ref int hackSide)
        {
// (C) CodeHimBelonga kdub@theSwamp 2010
//
            PromptPointResult ppr;
            PromptPointOptions ppo = new PromptPointOptions("");

            PromptEntityOptions peo = new PromptEntityOptions("\nSelect a PolyLine segment, or[Points]", "Points");
            peo.AllowNone = true;
            peo.SetRejectMessage("\nIncorrect entity");
            peo.AddAllowedClass(typeof(Polyline), true);
            peo.Keywords.Default = "Points";
            PromptEntityResult per = ed.GetEntity(peo);
            switch(per.Status) {
                case PromptStatus.Cancel:
                    return false;
                case PromptStatus.OK:
                    Point3d p0;
                    Point3d p1;
                    using(Transaction tr = db.TransactionManager.StartTransaction()) {
                        Polyline pline = (Polyline)tr.GetObject(per.ObjectId, OpenMode.ForRead);
                        Point3d pickPt = pickPointOnPline(pline, per.PickedPoint);
                        double param = pline.GetParameterAtPoint(pickPt);
                        int index = (int)param;
                        p0 = pline.GetPoint3dAt(index);

                        if(pline.Closed == false)
                            p1 = pline.GetPoint3dAt(index + 1);
                        else {
                            try { p1 = pline.GetPoint3dAt(index + 1); } catch { p1 = pline.GetPoint3dAt(0); }
                        }

                        if(pickPt.DistanceTo(p0) <= pickPt.DistanceTo(p1)) {
                            ptStart = p0;
                            ptEnd = p1;
                        } else {
                            ptStart = p1;
                            ptEnd = p0;
                        }
                        tr.Commit();
                    }

                    break;
                case PromptStatus.Keyword:
                    switch(per.StringResult) {
                        case "Points":
                            // Prompt for the start point
                            ppo.Message = "\nEnter the start point of the line: ";
                            ppr = ed.GetPoint(ppo);
                            ptStart = ppr.Value;

                            // Exit if the user presses ESC or cancels the command
                            if(ppr.Status == PromptStatus.Cancel)
                                return false;

                            // Prompt for the end point
                            ppo.Message = "\nEnter the end point of the line: ";
                            ppo.UseBasePoint = true;
                            ppo.BasePoint = ptStart;
                            ppr = ed.GetPoint(ppo);
                            ptEnd = ppr.Value;

                            if(ppr.Status == PromptStatus.Cancel)
                                return false;
                            break;

                        default:
                            return false;
                    }
                    break;
            }
            Matrix3d UCSMatrix = ed.CurrentUserCoordinateSystem;
            CoordinateSystem3d UCS = UCSMatrix.CoordinateSystem3d;
            Plane xyPlane = new Plane(ptStart, UCS.Xaxis, UCS.Yaxis);
            double angle0 = (ptEnd - ptStart).AngleOnPlane(xyPlane);

            Int16 osmode = (Int16)AcadApp.GetSystemVariable("OSMODE");
            double snapang = (double)AcadApp.GetSystemVariable("SNAPANG");
            AcadApp.SetSystemVariable("OSMODE", 1);
            AcadApp.SetSystemVariable("SNAPANG", angle0);

            Point3d ptSide = new Point3d();
            // Prompt for the HackSide           
            ppo.Message = "\nSelect the hack direction : ";
            ppo.UseBasePoint = true;
            ppo.BasePoint = ptStart;
            ppr = ed.GetPoint(ppo);
            ptSide = ppr.Value;

            AcadApp.SetSystemVariable("OSMODE", osmode);
            AcadApp.SetSystemVariable("SNAPANG", snapang);

            if(ppr.Status == PromptStatus.Cancel)
                return false;

            //-1 if ptSide is on left side
            //+1 if ptSide is on right side
            hackSide = ExtensionTools.DeflectionSide(ptStart, ptEnd, ptSide);

            return true;
        }

        // Credit to Gile @theSwamp
        private Point3d pickPointOnPline(Polyline pl, Point3d pt)
        {
            pt = pt.TransformBy(ed.CurrentUserCoordinateSystem);
            Vector3d vdir = ed.GetCurrentView().ViewDirection;
            pt = pt.Project(pl.GetPlane(), vdir);
            return pl.GetClosestPointTo(pt, false);
        }


ExtensionTools
Code: [Select]

// (C) CodeHimBelonga kdub@theSwamp 2010
//
using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace kdub_Testing
{
    public static class ExtensionTools
    {
        /// <summary>
        ///
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db"></param>
        /// <param name="numCols"></param>
        /// <param name="displacementVector"></param>
        public static void ArrayInAxis(this ObjectId id, Database db, int numCols, Vector3d displacementVector )
        {
            using(Transaction tr = db.TransactionManager.StartTransaction()) {
                BlockTable table = tr.GetObject(db.BlockTableId, OpenMode.ForRead, false) as BlockTable;
                BlockTableRecord record = tr.GetObject(table[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false) as BlockTableRecord;
                Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity;

                for(int j = 0; j < numCols; j++) {
                    Matrix3d transform = Matrix3d.Displacement(new Vector3d(j * displacementVector.X, j * displacementVector.Y, j * displacementVector.Z));
                    Entity transformedCopy = ent.GetTransformedCopy(transform);
                    record.AppendEntity(transformedCopy);
                    tr.AddNewlyCreatedDBObject(transformedCopy, true);
                }
                ent.Erase();
                tr.Commit();
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="ent"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static ObjectId AddToCurrentSpaceAndClose(Entity ent, Database db)
        {
            ObjectId objId;
            using(Transaction tr = db.TransactionManager.StartTransaction()) {
                objId = AddToCurrentSpace(ent, db, tr);
                tr.Commit();
            }
            return objId;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="ent"></param>
        /// <param name="db"></param>
        /// <param name="tr"></param>
        /// <returns></returns>
        public static ObjectId AddToCurrentSpace(Entity ent, Database db, Transaction tr)
        {
            ObjectId objId;
            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
            objId = btr.AppendEntity(ent);
            tr.AddNewlyCreatedDBObject(ent, true);
            return objId;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        /// Returns -1 if p3 is on left side of vector p1-p2,
        /// or returns +1 if p3 is on right side of vector p1-p2.
        /// Points are converted to XY plane.
        /// <returns></returns>
        public static int DeflectionSide(Point3d p1, Point3d p2, Point3d p3)
        {
            return DeflectionSide(
                new Point2d(p1.X, p1.Y),
                new Point2d(p2.X, p2.Y),
                new Point2d(p3.X, p3.Y)
                );
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        /// Returns -1 if p3 is on left side of vector p1-p2,
        /// or returns +1 if p3 is on right side of vector p1-p2.
        /// Points are converted to XY plane.
        /// <returns></returns>

        public static int DeflectionSide(Point2d p1, Point2d p2, Point2d p3)
        {           
            return (((p2.X - p1.X) * (p3.Y - p1.Y)) - ((p2.Y - p1.Y) * (p3.X - p1.X)) > 0) ? -1 : 1;
        }

    }
}


ANd the Project/Solution
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 #21 on: December 23, 2010, 12:07:16 AM »
Hi Kerry

I really thank you very much for all the trouble you took to give me a complete project. It is nice and easy to understand. I really appreciate your help.
I have started to change my code and once I am successful with output I shall post here to let you know.

Thanks & Regards,
Sachin

kaefer

  • Guest
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #22 on: December 23, 2010, 05:06:08 AM »
Code: [Select]
// (C) CodeHimBelonga kdub@theSwamp 2010
...
    public class LittleBoxes
    {
        Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
        Database db = HostApplicationServices.WorkingDatabase;

        [CommandMethod("HACK3")]
        public void HACK3()
        {
        ...

Hi Kerry,

am I allowed to do a little critiquing?

Well done.

The implicit constructor technique above got me stumped at first, but I recognize their value, especially when these fields are made public for later consumption by additional modules.

Quote
Code: [Select]
                ...
                BlockTableRecord record = tr.GetObject(table[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false) as BlockTableRecord;
                Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity;

                for(int j = 0; j < numCols; j++) {
                    Matrix3d transform = Matrix3d.Displacement(new Vector3d(j * displacementVector.X, j * displacementVector.Y, j * displacementVector.Z));
                    ...

Here the Modelspace is hardcoded, so HACK3 won't work in Paperspace.

The last line could surely be written as
Code: [Select]
                    Matrix3d transform = Matrix3d.Displacement(displacementVector.MultiplyBy(j));

Otherwise it's very difficult for me to localize possible further gnats in the ointment.

Take it easy, Thorsten

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #23 on: December 23, 2010, 05:12:43 AM »
Hi kaefer
Quote
am I allowed to do a little critiquing?
absolutely   :laugh: 


I appreciate the feedback.

Regarding Modelspace/paperspace ..
I can't think of any logical reason why anyone would want to do this sort of detailing in Paperspace.

Thankfully the issue is easily resolved by using 'CurrentSpace' if required. ... but good point :)

Quote
The last line could surely be written as
Code: [Select]
                   Matrix3d transform = Matrix3d.Displacement(displacementVector.MultiplyBy(j));

yes it could I think .. good eye !
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.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #24 on: December 23, 2010, 05:34:36 AM »
Sachin,

Regarding the distance to the first rectangle.
Are there cases where it must be a specific distance from the StartPoint ?

It's a little hard to know your process without understanding your product.
For instance, are the slabs solid or cored ?
If cored, is the knockout location related to the core location ?

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 #25 on: December 23, 2010, 06:05:04 AM »
Hi Kerry

Actually yes, it starts at specific distance from the bottom or top. The cores are parallel to the Slabs. There are 2 kinds of hacking. One is on cores and other one is on side which is perpendicular to the cores or length of the slab. The core hacking, fortunately I was able to do it, because I used cores as base objects. But these ones were becoming difficult. These hackings are perpendicular to slab length. You can see the attached image and you will get the idea. The yellow boxes are the result of your help and the core lines are in light gray which are perpendicular to the these rectangles.

Note: To the rectangle I also add Hatch so you may not see the boxes clearly.

Kerry

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


ok, be back in a bit ..
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.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Draw rectangles at regular interval on Polyline, Badly need in help...
« Reply #27 on: December 23, 2010, 06:50:11 AM »
Hack this into the  HACK3() method
Code: [Select]
//< .... snip  >
            if(proceed == false) {
                System.Windows.Forms.MessageBox.Show("You Made Boo-Boo Selection",
                    "Oooops",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation
                    );
                return;
            }
            Vector3d v1 = (Vector3d)(ptEnd - ptStart);
            double wpLen = v1.Length;

            // revised to marker - Prompt to confirm first space <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

            int spacingCount = (int)((wpLen / spacing) - 2);
            int firstDim = (int)((wpLen - (spacingCount * spacing) - width) / 2) ;

            PromptIntegerOptions pio = new PromptIntegerOptions("\nSpacing to CenterLine of First Hackout");
            pio.AllowNegative = false;
            pio.AllowZero = false;
            pio.AllowNone = false;
            pio.DefaultValue = firstDim + (int)(width * 0.5);
            PromptIntegerResult pir = ed.GetInteger(pio);
            if(pir.Status == PromptStatus.OK)
                firstDim = pir.Value - (int)(width * 0.5);

            spacingCount = (int)( ( ( wpLen - firstDim )  / spacing) - 1);

            pio = new PromptIntegerOptions("\nHackout quantum");
            pio.AllowNegative = false;
            pio.AllowZero = false;
            pio.AllowNone = false;
            pio.DefaultValue = (spacingCount + 1);

            pir = ed.GetInteger(pio);
            if(pir.Status == PromptStatus.OK)
                spacingCount = pir.Value - 1;

            Vector3d spacingVector = v1.MultiplyBy(spacing / wpLen);
            Vector3d firstVec = v1.MultiplyBy(firstDim / wpLen) ;
            
            //revised ^^^ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

            // draw first box
//< .... snip  >

« Last Edit: December 23, 2010, 07:08:42 AM by Kerry »
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.