Author Topic: VB.NET routine  (Read 6314 times)

0 Members and 1 Guest are viewing this topic.

rjohnson42

  • Guest
VB.NET routine
« on: January 11, 2011, 02:59:18 PM »
Hey fellas, I'm fairly new to VB and the .NET platform (2-3 weeks experience) and I'm having trouble determining a strategy to go about a problem I have. I would appreciate any help/advice about the situation; I'm not asking for lines and lines of code. I'm simply looking for a strategy to help guide me through the process.

Here's my problem: I would like to break multiple horizontal lines (red) at the intersection of multiple perpendicular lines (green). These lines will be defined by their respective layer in the code; the white polygon you see is the outline of the structure and should not affect the breaking of the horizontal lines. After the break, the start point and end point of each horizontal line should be set by the intersection of the perpendicular lines. I've attached a snapshot to help in the explanation.

Thanks and have a good one,

Robert


dan.glassman

  • Guest
Re: VB.NET routine
« Reply #1 on: January 11, 2011, 03:20:36 PM »
Filter all the lines into two lists -- the breaker lines and the breakable lines.  Several examples on this forum of iterating modelspace or filtering with SelectionSet to create these lists.

For each breakable line, find intersection points with all breaker lines [Entity.IntersectWith()].  Split the breakable at each intersection [Curve.GetSplitCurves()].

-drg

rjohnson42

  • Guest
Re: VB.NET routine
« Reply #2 on: January 11, 2011, 03:40:05 PM »
Filter all the lines into two lists -- the breaker lines and the breakable lines.  Several examples on this forum of iterating modelspace or filtering with SelectionSet to create these lists.

For each breakable line, find intersection points with all breaker lines [Entity.IntersectWith()].  Split the breakable at each intersection [Curve.GetSplitCurves()].

-drg


Thanks, Dan. I'll attempt to throw something together and repost within the next few hours.

kaefer

  • Guest
Re: VB.NET routine
« Reply #3 on: January 11, 2011, 04:22:43 PM »
Filter all the lines into two lists -- the breaker lines and the breakable lines.  Several examples on this forum of iterating modelspace or filtering with SelectionSet to create these lists.

For each breakable line, find intersection points with all breaker lines [Entity.IntersectWith()].  Split the breakable at each intersection [Curve.GetSplitCurves()].

-drg

I've found that mapping the intersection points to a sorted DoubleCollection of curve parameters works best with GetSplitCurves, to avoid breaking into overlapping curve segments.

Quote
Thanks, Dan. I'll attempt to throw something together and repost within the next few hours.

How's it going? Do you want a spoiler right now?
« Last Edit: January 11, 2011, 05:15:00 PM by kaefer »

dan.glassman

  • Guest
Re: VB.NET routine
« Reply #4 on: January 11, 2011, 04:53:24 PM »
Quote
I've found that mapping the intersection points to a sorted DoubleCollection of curve parameters works best with GetSplitCurves, to avoid breaking into overlapping curve segments.

I hadn't run into the overlaps, yet.  Thank you for the advice!

-drg

rjohnson42

  • Guest
Re: VB.NET routine
« Reply #5 on: January 11, 2011, 05:08:06 PM »
I've found that mapping the intersection points to a sorted DoubleCollection of curve parameters works best with GetSplitCurves, to avoid breaking into overlapping curve segments.

I'll have to read into this a bit more to fully understand how to use the DoubleCollection. It sounds like the DoubleCollection would be used to prevent multiple lines from crossing a perpendicular line, but I'm not entirely sure how to implement this just yet. This is the first I've heard of the DoubleCollection class, so it'll be a few before I can see exactly how to use it or map to it.

Quote
How's it going? Do you want a spoiler right now?

I will certainly take a spoiler!

Thanks for the help

fixo

  • Guest
Re: VB.NET routine
« Reply #6 on: January 11, 2011, 06:53:38 PM »
iIn case you've stacked with it, change object names and layer names in filter

Code: [Select]

        public static void BreakLines()
        {
            Database db = HostApplicationServices.WorkingDatabase;

            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;

            Editor ed = doc.Editor;

            using (DocumentLock doclock = doc.LockDocument())
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    try
                    {
                        ed.WriteMessage("\nSelect vertical lines\n");
                        PromptSelectionResult res = ed.GetSelection(
                            new PromptSelectionOptions(),
                            new SelectionFilter(new TypedValue[] { new TypedValue(0, "line"), new TypedValue( (int)DxfCode.LayerName,"grid" )}));
                        if (res.Status != PromptStatus.OK)
                            return;

                        ObjectId[] verIds = res.Value.GetObjectIds();

                        ed.WriteMessage("\nSelect horizontal polylines");
                        res = ed.GetSelection(
                            new PromptSelectionOptions(),
                            new SelectionFilter(new TypedValue[] { new TypedValue(0, "lwpolyline"), new TypedValue((int)DxfCode.LayerName, "Defpoints") }));

                        if (res.Status != PromptStatus.OK)
                            return;

                        ObjectId[] horIds = res.Value.GetObjectIds();

                        BlockTableRecord btr =
                            (BlockTableRecord)tr.GetObject(
                                db.CurrentSpaceId,
                                OpenMode.ForWrite,
                                false);
                        for (int i = 0; i < horIds.Length; i++)
                        {

                            Polyline lh = (Polyline)tr.GetObject(horIds[i], OpenMode.ForRead);
                            Curve ch = lh as Curve;
                            Point3dCollection allpts = new Point3dCollection();
                            foreach (ObjectId id in verIds)
                            {
                                Line lv = (Line)tr.GetObject(id, OpenMode.ForRead);
                                Curve cv = lv as Curve;
                                Point3dCollection pts = new Point3dCollection();
                                ch.IntersectWith(lv, Intersect.OnBothOperands, pts, 0, 0);
                                if (pts.Count > 0)
                                {
                                    foreach (Point3d pt in pts)
                                        allpts.Add(pt);
                                }
                            }
                            List<double> lst= new List<double>();
                            DoubleCollection pars = new DoubleCollection();
                            foreach (Point3d pt in allpts)   
                               lst.Add(ch.GetParameterAtPoint(pt));

                            lst.Sort();
                            foreach (double param in lst)
                                pars.Add(param);
                            DBObjectCollection objs = lh.GetSplitCurves(pars);
                            foreach (DBObject obj in objs)
                            {
                                Entity en = obj as Entity;
                                btr.AppendEntity(en);
                                tr.AddNewlyCreatedDBObject(en, true);
                                lh.UpgradeOpen();
                                lh.Erase();       
                            }
                                                       
                        }
                     
                        tr.Commit();
                    }

                    catch (Autodesk.AutoCAD.Runtime.Exception ex)
                    {
                        ed.WriteMessage(ex.Message);
                    }
                }
            }
        }

kaefer

  • Guest
Re: VB.NET routine
« Reply #7 on: January 11, 2011, 07:43:05 PM »
I'll have to read into this a bit more to fully understand how to use the DoubleCollection. It sounds like the DoubleCollection would be used to prevent multiple lines from crossing a perpendicular line, but I'm not entirely sure how to implement this just yet. This is the first I've heard of the DoubleCollection class, so it'll be a few before I can see exactly how to use it or map to it.

The problem mentioned may occur if you pass a Point3dCollection to Curve.GetSplitCurves, in which the points are either unordered or in reverse order in respect to the direction of the Curve.  There's an overload which takes a DoubleCollection instead; much easier to sort.

AutoCAD's collection classes (implementions of System.Collection.ICollection) predate .NET generics, so I think they have a certain quaint whiff about them. They can be quite powerful when used for parameter passing, as in our Entity.IntersectWith call, where a Point3dCollection has to be given in which the intersection points are returned.

Quote
I will certainly take a spoiler!

I'm glad that fixo saved the day (thx!), since I've got carried away and tried to create the ultimate tool again. Happens almost always to me.

Compare his slick C# with my humble F#:
Code: [Select]
module BreakAtIntersections

open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime

type acApp = Autodesk.AutoCAD.ApplicationServices.Application

// Modify Database. Take two ObjectId arrays,
// return tuple curvesCreated:int * curvesDeleted:int
let breakAtIntersections breakers breakables =
    let db = acApp.DocumentManager.MdiActiveDocument.Database
    let curvesCreated = ref 0
    let curvesDeleted = ref 0   
    use tr = db.TransactionManager.StartTransaction()
   
    // Check one breakable (henceforth known as "The Curve", as long
    // it's in scope) against intersections with breakers; split it
    // accordingly, if any
    let breakCurveAtIntersections curveId =
        let cur = tr.GetObject(curveId, OpenMode.ForRead) :?> Curve

        // Acquire intersections between The Curve and another curve
        // (cast as Entity here), return array of curve parameters
        let intersectionParams oid =
            let ent = tr.GetObject(oid, OpenMode.ForRead) :?> Entity
            let pts3dCollection = new Point3dCollection()
            cur.IntersectWith(ent, Intersect.OnBothOperands, pts3dCollection, 0, 0)
            [| for pt in pts3dCollection -> cur.GetParameterAtPoint pt |]

        // Split The Curve, open The Curve's owner BTR (would be Modelspace
        // normally), add the new entities to it, finally delete The Curve.
        let splitAtParams parameter =
            if not(Array.isEmpty parameter) then
                let btr =
                    tr.GetObject(cur.OwnerId, OpenMode.ForWrite, false)
                        :?> BlockTableRecord
                let dBObjectCollection =
                    new DoubleCollection(parameter)
                    |> cur.GetSplitCurves
                for dbo in dBObjectCollection do
                    let ent = dbo :?> Entity
                    btr.AppendEntity ent |> ignore
                    tr.AddNewlyCreatedDBObject(ent, true)
                    incr curvesCreated
                if dBObjectCollection.Count > 0 then
                    cur.UpgradeOpen()
                    cur.Erase()
                    incr curvesDeleted

        // Inner loop. Apply The Curve against each breaker,
        // flatten and sort the returned arrays, split
        breakers
        |> Array.collect intersectionParams
        |> Array.sort
        |> splitAtParams

    // Outer loop. Apply each breakable against all breakers
    breakables |> Array.iter breakCurveAtIntersections
    tr.Commit()
    !curvesCreated, !curvesDeleted

// Custum operator and helper for user selection filter supplied to
// the SelectionAdded event
let (+=) e f = Observable.subscribe f e
let selectionIndexed =
    Seq.cast<SelectedObject> >> Seq.mapi (fun i so -> i, so.ObjectId)

[<CommandMethod "BAI">]
let breakAtIntersectionsCommand () =
    let ed = acApp.DocumentManager.MdiActiveDocument.Editor

    // Partial Active Pattern, matches selection message with
    // ObjectId array option, after setting up a self-disposing
    // event listener that filters all non-Curves
    let (|Select|_|) msg =
        use selectionAdded =
            ed.SelectionAdded +=
                fun e ->
                    for (i, oid) in selectionIndexed e.AddedObjects do
                        if  RXClass.GetClass(typeof<Curve>)
                            |> oid.ObjectClass.IsDerivedFrom
                            |> not then e.Remove i
        let psr =
            new PromptSelectionOptions(MessageForAdding = msg)
            |> ed.GetSelection
        if psr.Status = PromptStatus.OK && psr.Value.Count > 0 then
            Some(psr.Value.GetObjectIds())
        else None
       
    // User input, short-circuit pattern matching
    match "Select breaker curves", "Select breakable curves" with
    | Select breakers, Select breakables ->
        let created, deleted =
            breakAtIntersections breakers breakables
        ed.WriteMessage(
            "\n{0} curve(s) created, {1} curve(s) deleted ",
            created, deleted )
    | _ -> ()

rjohnson42

  • Guest
Re: VB.NET routine
« Reply #8 on: January 12, 2011, 09:26:46 AM »
Thank you for the replies/help, guys. I'm going to look at fixo's code and see if I can replicate it in VB.

If anyone is interested, another swamp user posted an awesome LISP routine here: http://www.theswamp.org/index.php?topic=10370.0

This does exactly what I need it to do, so I may just end up using it. Although I would like to make some modifications ;)

Have a good one,

Robert