Тема: Поиск блока (объекта) по щелчку

Здравствуйте!

У меня к Вам следующий вопрос.
На чертеже есть много замкнутых непересекающихся контуров. Допустим, они представляют собой замкнутые полилинии.
Моя задача - по щелчку пользователя найти контур, внутри которого был произведён щелчёк.

Пишу на C#.

Первое, что приходит в голову:
1) Реализовать проверку принадлежности точки замкнутой полилинии.
2) Найти все контуры, в BoundaryBox которых попадает входная точка.
3) Проверить каждый на попадание.

Выглядит как-то сложно для такой простой, на первый взгляд, задачи.

Я сначала пошёл другим путём. Я думал, что метод Editor.Snap(snapMode, inputPoint) возвращает ближайшую точку привязки. Тогда я бы выбрал режим привязки "ближайшая", и получил бы точку на ближайшем контуре. Вероятнее всего это и был бы искомый контур. Но, на сколько я понял, этот метод делает совершенно не это...

Может, есть какие-нибудь нативные способы реализации этой простой задачи? Я думал ещё использовать TraceBoundary, но он создаёт новые объекты (вернее объект, в моём случае). А мне нужен именно тот объект, который на чертеже.
Может, если преобразовать контуры в блоки - будет легче?

Спасибо за Вашу помощь!

Re: Поиск блока (объекта) по щелчку

Я бы все твои полигоны нарисовал на своем слое
Тогда не надо тыкать мышкой куда чего писать
Например как здесь, пробуй

        [CommandMethod("LabelAreaFields", "lap", CommandFlags.Modal | CommandFlags.Redraw)]

        public void AddAreaFields()
        {

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

            Database db = doc.Database;

            Editor ed = doc.Editor;

            SelectionFilter filter = new SelectionFilter(new TypedValue[] 
            { 
                new TypedValue(0, "LWPOLYLINE"), 
                new TypedValue(70, 1),//    <--- closed polylines
                new TypedValue(8, "A-ROOM")//    <--- layer of polylines
            });

            PromptSelectionResult res = ed.GetSelection(filter);

            if (res.Status != PromptStatus.OK)
            {

                ed.WriteMessage("\nerror in getting the 'GetSelection'");

                return;

            }
            SelectionSet ssobj = res.Value;

            if (ssobj.Count == 0) return;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                foreach (SelectedObject selobj in ssobj)
                {
                    DBObject dbo = (DBObject)tr.GetObject(selobj.ObjectId, OpenMode.ForRead, false);

                    Polyline poly = dbo as Polyline;

                    Extents3d ext = poly.GeometricExtents;

                    Point3d p1 = ext.MinPoint;

                    Point3d p2 = ext.MaxPoint;

                    Point3d center = new Point3d(
                        (p1.X + p2.X) / 2,
                        (p1.Y + p2.Y) / 2,
                        (p1.Z + p2.Z) / 2);

                    string stroid = poly.ObjectId.ToString().Trim('(', ')');

                    string pref = "%<\\AcObjProp Object(%<\\_ObjId ";

                    string suff = ">%).Area \\f \"%lu2%pr2\">%";    //  <--- decimal units, precision 2

                    string strfield = string.Concat(pref, stroid, suff);

                    MText mtx = new MText();

                    mtx.SetDatabaseDefaults();

                    mtx.Location = center;

                    mtx.Attachment = AttachmentPoint.MiddleCenter;

                    //      Set mtext height and style to your needs here     //

                    BlockTableRecord btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;

                    btr.AppendEntity(mtx);

                    tr.AddNewlyCreatedDBObject(mtx, true);

                    Field fld = new Field(strfield);

                    fld.Evaluate();

                    mtx.SetField(fld);

                    tr.AddNewlyCreatedDBObject(fld, true);

                }
                tr.Commit();
            }
        }

Re: Поиск блока (объекта) по щелчку

Спасибо за быстрый ответ!
Но, к сожалению, мне надо определить контур именно по щелчку внутри него. Фактически, мне надо назначить этому контуру направление (первый щелчок - внутри контура, второй - для определения направления). Типа "заливки" контура штриховкой с направлением.
Так что подход "GetSelection" в данном случае на совсем удобен...

(изменено: Boxa Shu, 17 января 2013г. 15:20:25)

Re: Поиск блока (объекта) по щелчку

Посмотрите все же в сторону TraceBoundary
Как найти объекты образующие контуры:

Kean Walmsley said in reply to Boxa...

You need to iterate through the entities you care about - a selection set or the contents of the model space, for instance - and then get the Extents of each one.

Kean

Подробнее тут : тынц

(изменено: Александр Ривилис, 17 января 2013г. 15:22:45)

Re: Поиск блока (объекта) по щелчку

Павел пишет:

Пишу на C#.

Первое, что приходит в голову: 1) Реализовать проверку принадлежности точки замкнутой полилинии. 2) Найти все контуры, в BoundaryBox которых попадает входная точка. 3) Проверить каждый на попадание.

Выглядит как-то сложно для такой простой, на первый взгляд, задачи.

Проще не будет. Тут вопрос не в простоте, а в скорости работы. В любом случае тебе понадобятся все контуры. И алгоритм определения попадания точки внутри контура.

Re: Поиск блока (объекта) по щелчку

Посмотри еще здесь
http://adndevblog.typepad.com/autocad/2 … g-net.html

Re: Поиск блока (объекта) по щелчку

Спасибо всем, буду пробовать...

Копать в сторону TraceBoundary не очень хочется. В основном из-за того, что контур весь обязательно должен быть в зоне видимости.

Александр Ривилис пишет:

... В любом случае тебе понадобятся все контуры. И алгоритм определения попадания точки внутри контура.

С этого и начну. реализаций алгоритма этого много видел. Интересно, какой бы взять за основу...

Re: Поиск блока (объекта) по щелчку

Павел пишет:

Интересно, какой бы взять за основу...

Любой. Например, трассировку луча - подсчет четности пересечения луча из указанной точки в любом направлении с каждым из контуров. Сначала для скорости можно проверить, что этот луч пересекает BoundingBox контура.

Re: Поиск блока (объекта) по щелчку

Спасибо! С этого и начну...

Re: Поиск блока (объекта) по щелчку

Можешь начать с этого,
не забудь добавить слой для полилиний


     using System.Collections.Specialized;
using System.Linq;
using System.Collections;
остальные namespaces.....
...._________________________________________..
  [CommandMethod("tpp", CommandFlags.UsePickSet | CommandFlags.Redraw)]

        public static void testPickPoint()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;

            Database db = doc.Database;

            Editor ed = doc.Editor;

            string curlay = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("CTAB").ToString();

            ObjectIdCollection ids = new ObjectIdCollection();

            SortedList<ObjectId, double> distances = new SortedList<ObjectId, double>();

            // Let our selection to only select closed polylines

            PromptSelectionOptions pso = new PromptSelectionOptions();

            pso.MessageForAdding = "\nSelect polygons";
            // Add polyline layer for better selection
            SelectionFilter filter = new SelectionFilter(new TypedValue[]  {
            new TypedValue((int)DxfCode.Start, "LWPOLYLINE"),
            new TypedValue(70, 1),
            new TypedValue((int)DxfCode.LayoutName, curlay)});

            PromptSelectionResult psr = ed.SelectAll(filter);

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

            if (psr.Value.GetObjectIds().Length == 0) return;

            try
            {
                Transaction tr = db.TransactionManager.StartTransaction();

                using (tr)
                {

                    foreach (SelectedObject selobj in psr.Value)
                    {
                        Polyline pline = tr.GetObject(selobj.ObjectId, OpenMode.ForRead) as Polyline;

                        if (pline != null)
                        {
                            ids.Add(pline.ObjectId);
                        }
                    }
                    if (ids == null) return;

                    Point3d pick;

                    PromptPointOptions opt = new PromptPointOptions("\nPick a point inside the polygon:");

                    PromptPointResult res = ed.GetPoint(opt);

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

                    pick = res.Value;



                    Point3d cp;

                    foreach (ObjectId id in ids)
                    {
                        DBObject obj = tr.GetObject(id, OpenMode.ForRead);

                        if (obj == null) return;

                        Polyline poly = obj as Polyline;

                        if (poly == null) return;
                        {
                            cp = poly.GetClosestPointTo(pick, false);

                            double dist = pick.DistanceTo(cp);

                            if (distances.ContainsKey(poly.ObjectId))
                            {
                                double dd = distances[poly.ObjectId];

                                if (dist < dd)
                                {
                                    distances[poly.ObjectId] = dist;
                                }
                            }
                            else
                            {
                                distances.Add(poly.ObjectId, dist);
                            }
                        }
                    }
                    // Retrieve minimal distance with relatively linked ObjectId
                    // Sort them
                    KeyValuePair<ObjectId, double> kvp = distances.OrderBy(x => x.Value).ElementAt(0);

                    DBObject found = tr.GetObject((ObjectId)kvp.Key, OpenMode.ForRead, false);

                    Polyline pl = found as Polyline;

                    ed.WriteMessage("\nПлощадь полигона:\t{0:f4}\n", pl.Area);
                    pl.UpgradeOpen();
                    pl.ColorIndex = 1;
                    pl.DowngradeOpen();

                    tr.Commit();
                    ed.Regen();
                }

            }
            catch (Autodesk.AutoCAD.Runtime.Exception ex)
            {
                Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage
                    (ex.Message + "\n" + ex.StackTrace);
                return;
            }
            finally
            {
                distances = null;// optional
            }
        }

Re: Поиск блока (объекта) по щелчку

fixo,
Спасибо большое!

Получается, так найдётся ближайшая полилиния к точке.
Наверное действительно, в большинстве случаев это и будет нужный контур.
А потом я проверю этот ближайший контур на попадание в него точки. По времени наверное достаточно оптимальный алгоритм. Попробую - отпишусь...

Re: Поиск блока (объекта) по щелчку

Хорошо бы знать результат,
я не проверял на больших чертежах,
удачи,