Author Topic: How can i find touching line objects at the end points?  (Read 3512 times)

0 Members and 1 Guest are viewing this topic.

cincir

  • Guest
How can i find touching line objects at the end points?
« on: July 05, 2012, 06:15:42 PM »
How can i find touching line objects at the end points without iterating through the blocktablerecord's entities?

SGP2012

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #1 on: July 05, 2012, 09:32:55 PM »
Whatever method you use, you'll ultimately be iterating entities - either in your code or behind the scenes. The exception being on screen selection, so you could try using the line start/end points to create a Fence selection. On screen selection uses the graphics cache (instead of iterating the database) to optimize peformance. The disadvantages are that it only works when the geometry is displayed on the screen and accuracy is reduced as you zoom out. If you have to zoom or pan your drawing to use this method, then you're probably better off iterating the database.

Editor.SelectFence().

Cheers,

Stephen

fixo

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #2 on: July 06, 2012, 04:57:42 AM »
How can i find touching line objects at the end points without iterating through the blocktablerecord's entities?
You can use PointMonitor event to get start point
with or without picking the lline, here is the code completely borrowed
from Kean Walmsley:
Code: [Select]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;

[assembly: CommandClass(typeof(AutoCAD_CSharp_plug_in1.EndTouch))]

namespace AutoCAD_CSharp_plug_in1
{
    public class EndTouch
    {
        [CommandMethod("SiM")]

        public static void StartMonitor()
        {

            Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;

            ed.PointMonitor += new PointMonitorEventHandler(ed_PointMonitor);

        }



        [CommandMethod("XiM")]

        public static void StopMonitor()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

            ed.TurnForcedPickOn();

            ed.PointMonitor -= new PointMonitorEventHandler(ed_PointMonitor);
        }

        public static void ed_PointMonitor(object sender, PointMonitorEventArgs e)
        {
            Editor ed = (Editor)sender;

            Document doc = ed.Document;

            double gap = (double)Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("dimtxt");
            try
            {
                FullSubentityPath[] paths = e.Context.GetPickedEntities();

                // Go through the results of the selection

                // and detect the curves

                // string curveInfo = "";

                Transaction tr = doc.TransactionManager.StartTransaction();

                using (tr)
                {
                    // Open each object, one by one

                    foreach (FullSubentityPath path in paths)
                    {

                        ObjectId[] ids = path.GetObjectIds();

                        if (ids.Length > 0)
                        {

                            ObjectId id = ids[ids.GetUpperBound(0)];

                            DBObject obj = tr.GetObject(id, OpenMode.ForRead);

                            if (obj != null)
                            {

                                // If it's a Line, get its start point
                                Line ln = obj as Line;

                                if (ln != null)
                                {
                                    double length = ln.GetDistanceAtParameter(ln.EndParam) - ln.GetDistanceAtParameter(ln.StartParam);

                                    // Then get start point of line

                                    Point3d pnt = ln.StartPoint;

                                    ed.DrawVector(new Point3d(pnt.X + gap, pnt.Y + gap, pnt.Z), new Point3d(pnt.X - gap, pnt.Y - gap, pnt.Z), 1, false);
                                    ed.DrawVector(new Point3d(pnt.X + gap, pnt.Y - gap, pnt.Z), new Point3d(pnt.X - gap, pnt.Y + gap, pnt.Z), 1, false);

                                }

                            }

                        }

                    }

                    tr.Commit();

                }

            }

            catch
            {

                // Not sure what we might get here, but not real action

                // needed (worth adding an Exception parameter and a

                // breakpoint, in case things need investigating).

            }

        }

    }
}

~'J'~

cincir

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #3 on: July 06, 2012, 09:43:59 AM »
Thank you fixo but i am thinking of selecting a line then trying to find the other lines those are touching the one that i selected at the end.

fixo

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #4 on: July 06, 2012, 10:05:11 AM »
to create chain selection just iterate through selected lines
then compare the ends / starts of these lines, nothing else

~'J'~

TheMaster

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #5 on: July 06, 2012, 11:47:19 AM »
Thank you fixo but i am thinking of selecting a line then trying to find the other lines those are touching the one that i selected at the end.

I'm not sure why you can't iterate over the entities in a BlockTableRecord, but that's really how it needs to be done. So, can I ask why you are imposing that restriction (e.g., 'without iterating through the blocktablerecord's entities' ?


cincir

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #6 on: July 06, 2012, 06:25:42 PM »
Simple because it takes too long  :-)

TheMaster

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #7 on: July 06, 2012, 10:05:27 PM »
Simple because it takes too long  :-)

If you want to limit the candidate objects/lines to only those
that are visible in the current view, you can use a window or
crossing selection to get them, and then do the search, but
when finding connecting lines, I wouldn't consider visiblity in
the current view as a legitimate constraint.

So, if the only way to do it correctly takes too long, then I guess
you are left with two possible choices: Do it correctly, or don't
do it at all.   :-D

fixo

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #8 on: July 08, 2012, 01:43:35 AM »
Simple because it takes too long  :-)

Try to adopt this code to your needs
Another way is to create selection set based on screen coordinates
to create it using CrossingWindow mode then iterate through
this selection set instead of looping entitre the whole BlockTableRecord,
just a hint...
Code: [Select]
        [CommandMethod("testJoinLines","tjl", CommandFlags.Modal | CommandFlags.UsePickSet)]
        public void TestConnectedLines()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;

            Editor ed = doc.Editor;

            Database db = doc.Database;

            PromptEntityOptions pso = new PromptEntityOptions("\nPick a single line to join: ");

            pso.SetRejectMessage("\nObject must be of type Line!");

            pso.AddAllowedClass(typeof(Line), false);

            PromptEntityResult res = ed.GetEntity(pso);

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

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead) as BlockTableRecord;

                List<ObjectId> ids = JoinLines(btr, res.ObjectId);

                ObjectId[] lines = ids.ToArray();

                ed.SetImpliedSelection(lines);
                //or
                //ed.SetImpliedSelection(ids.OfType<ObjectId>().ToArray());
                PromptSelectionResult chres = ed.SelectImplied();

                if (chres.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("\nNothing added in the chain!");

                    return;
                }


                foreach (SelectedObject selobj in chres.Value)
                {

                    Entity subent = tr.GetObject(selobj.ObjectId, OpenMode.ForWrite) as Entity;

                    subent.ColorIndex = 4;
                }

 
                tr.Commit();
            }
           
        }

        private void SelectConnectedLines(BlockTableRecord btr, List<ObjectId> ids, ObjectId id)
        {
            Entity en = id.GetObject(OpenMode.ForRead, false) as Entity;

            Line ln = en as Line;

            if (ln != null)

                foreach (ObjectId idx in btr)
                {
                    Entity ex = idx.GetObject(OpenMode.ForRead, false) as Entity;

                    Line lx = ex as Line;

                    if (((ln.StartPoint == lx.StartPoint) || (ln.StartPoint == lx.EndPoint)) ||

                        ((ln.EndPoint == lx.StartPoint) || (ln.EndPoint == lx.EndPoint)))

                        if (!ids.Contains(idx))
                        {
                            ids.Add(idx);

                            SelectConnectedLines(btr, ids, idx);
                        }
                }
        }

        public List<ObjectId> JoinLines(BlockTableRecord btr, ObjectId id)
        {
            List<ObjectId> ids = new List<ObjectId>();

            SelectConnectedLines(btr, ids, id);

            return ids;
        }

~'J'~
« Last Edit: July 08, 2012, 01:47:55 AM by fixo »

cincir

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #9 on: July 08, 2012, 10:12:21 PM »
Thank you for the sample code fixo. but i have got a huge file and i have already tried this. believe me it is very time comsuming when iterate all the entities. but again thanks anyway.

Gasty

  • Newt
  • Posts: 90
Re: How can i find touching line objects at the end points?
« Reply #10 on: July 09, 2012, 01:00:59 AM »
Hi,


How many lines have in the dwg?, Can you use a third party library? if so, you can try with quick graph in this link: http://quickgraph.codeplex.com/ (it's free) you only need to create a graph (just an object of the library), add by range the vertex collection (nodes or line end points in this case) , and edge collection (the source and target vertex (node): the start and end point of each line)  and that's it, with 20 or less lines of code you have a query-able graph. The main issue with this approach is rounding, so you need to take care of that as the vertex collection need to be exclusive (no repeated nodes).

Gaston Nunez




Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: How can i find touching line objects at the end points?
« Reply #11 on: July 09, 2012, 01:12:34 AM »
cincir,
You may need to provide a bit more detail regarding what you expect.

Are you expecting to return a list of ALL lines that have connecting lines each end. ??

How big is your drawing ?
Do you have a sample ?

What time do you expect this calculation to take. ?

How do you imagine this could be done WITHOUT iterating the database ??

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.

pkohut

  • Bull Frog
  • Posts: 483
Re: How can i find touching line objects at the end points?
« Reply #12 on: July 09, 2012, 01:36:40 AM »
Hey Fixo,

Some premature optimization here  :-D
1) check if ObjectId is in the container before comparing endpoints in SelectConnectedLines
2) Depending on number of potential objects the List<> can have, switch to a Dictionary or HybridDictionary class for SelectConnectedLines.

New tread (not retired) - public repo at https://github.com/pkohut

fixo

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #13 on: July 09, 2012, 04:18:05 AM »
Hey Fixo,

Some premature optimization here  :-D
1) check if ObjectId is in the container before comparing endpoints in SelectConnectedLines
2) Depending on number of potential objects the List<> can have, switch to a Dictionary or HybridDictionary class for SelectConnectedLines.

Thanks Paul, this one is written quickly from scratch,
I will see what I can do, but would be this easier to
use selection set of lines on the current tab instead?
Regards,

Oleg

fixo

  • Guest
Re: How can i find touching line objects at the end points?
« Reply #14 on: July 09, 2012, 05:05:24 AM »
Thank you for the sample code fixo. but i have got a huge file and i have already tried this. believe me it is very time comsuming when iterate all the entities. but again thanks anyway.
Try this one instead, it takes about 30 sec on 16000 lines on my machine
Code: [Select]

        [CommandMethod("testJoinLines", "tjl", CommandFlags.Modal | CommandFlags.UsePickSet)]//OK
        public void TestConnectedLines()
        {
           
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;

            Editor ed = doc.Editor;

            Database db = doc.Database;

            PromptEntityOptions pso = new PromptEntityOptions("\nPick a single line to join: ");

            pso.SetRejectMessage("\nObject must be of type Line!");

            pso.AddAllowedClass(typeof(Line), false);

            PromptEntityResult res = ed.GetEntity(pso);

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

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead) as BlockTableRecord;

               Layout lt = (Layout)tr.GetObject(btr.LayoutId, OpenMode.ForRead) as Layout;

               TypedValue[] values = new TypedValue[]
                     {
                        new TypedValue(0, "LINE") ,
                        new TypedValue(410, lt.LayoutName)
                     };
               SelectionFilter filter = new SelectionFilter(values);

               PromptSelectionResult result = ed.SelectAll(filter);
               if (result.Status != PromptStatus.OK) return;
               SelectionSet sset = result.Value;
               
                List<ObjectId> ids = JoinLines(sset, res.ObjectId);

                ObjectId[] lines = ids.ToArray();

                ed.SetImpliedSelection(lines);
                //or
                //ed.SetImpliedSelection(ids.OfType<ObjectId>().ToArray());
                PromptSelectionResult chres = ed.SelectImplied();

                if (chres.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("\nNothing added in the chain!");

                    return;
                }


                foreach (SelectedObject selobj in chres.Value)
                {

                    Entity subent = tr.GetObject(selobj.ObjectId, OpenMode.ForWrite) as Entity;

                    subent.ColorIndex = 4;
                }


                tr.Commit();
            }

        }

 
        private void SelectConnectedSet(SelectionSet sset, List<ObjectId> ids, ObjectId id)
        {
            Entity en = id.GetObject(OpenMode.ForRead, false) as Entity;

            Line ln = en as Line;

            if (ln != null)

                foreach (SelectedObject selobj in sset)
                {
                    ObjectId idx = selobj.ObjectId;
                    if (!idx.IsValid) continue;
                    Entity ex = idx.GetObject(OpenMode.ForRead, false) as Entity;

                    Line lx = ex as Line;

                    if (((ln.StartPoint == lx.StartPoint) || (ln.StartPoint == lx.EndPoint)) ||

                        ((ln.EndPoint == lx.StartPoint) || (ln.EndPoint == lx.EndPoint)))

                        if (!ids.Contains(idx))
                        {
                            ids.Add(idx);

                            SelectConnectedSet(sset, ids, idx);
                        }
                }
        }


        public List<ObjectId> JoinLines(SelectionSet sset, ObjectId id)
        {
            List<ObjectId> ids = new List<ObjectId>();

            SelectConnectedSet(sset, ids, id);

            return ids;
        }

~'J'~