(изменено: Дмитрий Гилин, 29 февраля 2012г. 17:36:53)

Тема: Объединение линий в одну полилинию

Здравствуйте, коллеги.
Есть вопрос по Autocad .Net API C#.

Задача.
Имеется полилиния (Polyline), содержащая прямолинейные участки и дуги.
Имеется вторая полилиния, скорее всего прямолинейная, но в общем случае необязательно.
Требуется второй линией разбить первую, т.е. добавить дополнительные узлы в точках пересечения линий.

Решаю следующим образом.
1. Методом Curve.IntersectWith() получаю точки пересечения, для проверки рисую в этих точках окружности красным цветом - да, точки пересечения найдены верно.
2. Методу Curve.GetSplitCurves() подсовываю полученные точки и получаю разбитую поллинию, для проверки рисую эти линии желтым - отлично, похоже на правду, пол задачи решено.
3. Пытаюсь объединить кусочки полилинии обратно в целую полилинию, вызываю метод Polyline.JoinEntities(), получаю исключение.
Не спрашивайте какое исключение, оно не информативное, ничего полезного не сообщает. Пробовал из исходной кривой исключать дуги, пробовал в качестве обеих полилиний использовать два простых отрезка - ничего не помогает.
4. Стал искать информацию по JoinEntities() на форуме автодеск, действительно проблема существует, но решения нет.
5. Решил последовательно пробежаться по кусочкам полилинии, полученным после GetSplitCurves() и создать из них новую полилинию, оказалось что после разбиения эти кусочки лежат в каком-то хаотичном порядке, вершины в произвольном направлении.
6. Сейчас сижу пишу алгоритм, который будет в этом хаосе отыскивать соседние кусочки, выправлять их направление и складывать вместе.

Но может быть есть способ элегантнее?
Спасибо.

Объединение линий в одну полилинию

P.S. перед публикацией топика увидел пример на лиспе по схожей проблеме
https://www.caduser.ru/forum/topic49414.html
но вопрос остается - хотелось бы реализовать на .Net

Re: Объединение линий в одну полилинию

Дмитрий Гилин пишет:

2. Методу Curve.GetSplitCurves() подсовываю полученные точки и получаю разбитую поллинию, для проверки рисую эти линии желтым - отлично, похоже на правду, пол задачи решено.

В каком порядке подсовываешь?

(изменено: Дмитрий Гилин, 1 марта 2012г. 09:31:39)

Re: Объединение линий в одну полилинию

Александр, примерно вот так:

Plane plane = new Plane(
  Application.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d.Origin,
Application.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d.Zaxis );

Point3dCollection intersections = new Point3dCollection();

// получение точек пересечения
curve1.IntersectWith( curve2, Intersect.OnBothOperands, plane, intersections, IntPtr.Zero, IntPtr.Zero );

// разделение полилинии на кусочки
DBObjectCollection splitObjects = curve1.GetSplitCurves( intersections );

// преобразование коллекции DBObject к коллекции Entity
Entity[] splitEntities = splitObjects.OfType< Entity >().ToArray();

using ( BlockTable blockTable = (BlockTable)transaction.GetObject( database.BlockTableId, OpenMode.ForRead ) )
{
    using ( BlockTableRecord blockTableRecord = (BlockTableRecord)transaction.GetObject( blockTable[ BlockTableRecord.ModelSpace ], OpenMode.ForWrite ) )
    {
        // добавление каждого кусочка разбитой полилинии в Record и в транзакцию 
        foreach ( Entity entity in splitEntities )
        {
            blockTableRecord.AppendEntity( entity );
            transaction.AddNewlyCreatedDBObject( entity, true );
        }

        // создание новой полилинии
        using ( Polyline polyline = new Polyline() )
        {
            // создание полилинии из кусочков
            polyline.JoinEntities( splitEntities ); // <- вот здесь происходит исключение

            blockTableRecord.AppendEntity( polyline );
            transaction.AddNewlyCreatedDBObject( polyline, true );
        }
    }
}

transaction.Commit();

Re: Объединение линий в одну полилинию

Найденные ссылки по теме (возможно нужна регистрация):
http://forums.autodesk.com/t5/NET/Polyl … rue#M22600
http://www.theswamp.org/index.php?topic=30636.0

(изменено: Александр Ривилис, 1 марта 2012г. 09:54:52)

Re: Объединение линий в одну полилинию

"Подсовываешь" неправильно. После получения точек пересечения тебе необходимо получить упорядоченный массив параметров для этих точек (Curve.GetParameterAtPoint) и вызывать Curve.GetSplitCurves, передавая именно этот массив. Вот тогда у тебя будут шансы, что кусочки будут не в хаотическом порядке.

Re: Объединение линий в одну полилинию

Шансы? т.е. никаких гарантий? спасибо, буду пробовать, отпишусь.

(изменено: Александр Ривилис, 1 марта 2012г. 10:04:18)

Re: Объединение линий в одну полилинию

Дмитрий Гилин пишет:

Шансы? т.е. никаких гарантий? спасибо, буду пробовать, отпишусь.

Так должно быть. Еще в массив параметров нужно добавить начальный и конечный параметры.
Второе: polyline.JoinEntities( splitEntities ); // <- вот здесь происходит исключение
Попробуй сначала присвоить polyline первый сегмент, а затем polyline.JoinEntities остальные сегменты без первого.
Третье: Никогда не пиши так:

Дмитрий Гилин пишет:

Не спрашивайте какое исключение, оно не информативное, ничего полезного не сообщает.

То что для тебя бесполезно для других может оказаться весьма полезным.
Четвертое:
Очень похоже, что это совершенно лишнее:

      // добавление каждого кусочка разбитой полилинии в Record и в транзакцию
      foreach ( Entity entity in splitEntities )
      {
         blockTableRecord.AppendEntity( entity );
         transaction.AddNewlyCreatedDBObject( entity, true );
      } 

Я посмотрел описание этого метода в ObjectARX и судя по всему примитивы, для которых выполняется JoinEntities не должны быть в базе чертежа.

Re: Объединение линий в одну полилинию

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

Третье: Никогда не пиши так:

Дмитрий Гилин пишет:

Не спрашивайте какое исключение, оно не информативное, ничего полезного не сообщает.

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

Я вчера торопился, некогда было восстанавливать код с исключением, вот текст:

Autodesk.AutoCAD.Runtime.Exception: eNotApplicable
   в Autodesk.AutoCAD.DatabaseServices.Entity.JoinEntities(Entity[] otherEntities)
   в Point.GeoSeries.AutocadInteraction.Backroom.Snooper.MainForm.button11_Click(Object sender, EventArgs e) в C:\Dmitry\...\Snooper\MainForm.cs:строка 890
   в System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   в System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   в System.Windows.Forms.Control.WndProc(Message& m)
   в System.Windows.Forms.ButtonBase.WndProc(Message& m)
   в System.Windows.Forms.Button.WndProc(Message& m)
   в System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
Александр Ривилис пишет:

Я посмотрел описание этого метода в ObjectARX и судя по всему примитивы, для которых выполняется JoinEntities не должны быть в базе чертежа.

Это исключительно для того, чтобы отобразить на экране полученные сегменты, т.е. для проверки.

Re: Объединение линий в одну полилинию

Еще в массив параметров нужно добавить начальный и конечный параметры.

не понял

Re: Объединение линий в одну полилинию

Дмитрий Гилин пишет:


Еще в массив параметров нужно добавить начальный и конечный параметры. [/quote пишет:


не понял


Имеется в виду Curve.StartParam и Curve.EndParam

Дмитрий Гилин]
Autodesk.AutoCAD.Runtime.Exception: eNotApplicable


Ну как раз это и означает, что "неприменимо". Возможно из-за неупорядоченности, возможно из-за того, что уже в базе.

Re: Объединение линий в одну полилинию

Александр, спасибо огромное, теперь работает!
Удачи вам в ваших проектах!

Приведу рабочий код:

Plane planeXoy = new Plane( 
 Application.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d.Origin,
 Application.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d.Zaxis
);

Point3dCollection intersectionPoints = new Point3dCollection();

// получение точек пересечения 
curve1.IntersectWith( curve2, Intersect.OnBothOperands, planeXoy, intersectionPoints, IntPtr.Zero, IntPtr.Zero );

List< double > intersectionDistances = new List< double >();

// получение дистанций точек пересечения
foreach ( Point3d intersectionPoint in intersectionPoints )
{
    intersectionDistances.Add( curve1.GetParameterAtPoint( intersectionPoint ) );
}

// добавление начала и конца кривой (БЕЗ ЭТИХ ДВУХ СТРОЧЕК ТОЖЕ РАБОТАЕТ)
intersectionDistances.Insert( 0, curve1.StartParam );
intersectionDistances.Add( curve1.EndParam );

// сортировка по дистанциям
intersectionDistances.Sort();

// получение участков кривых рассеченной полилинии
DBObjectCollection splitCurves = curve1.GetSplitCurves( new DoubleCollection( intersectionDistances.ToArray() ) );

// преобразование в участков кривых в коллекцию Entity, фактически это коллекция Polyline
IList< Entity > splitEntities = splitCurves.OfType< Entity >().ToList();

if ( splitEntities.Count > 0 )
{
    using ( BlockTable blockTable = (BlockTable)transaction.GetObject( database.BlockTableId, OpenMode.ForRead ) )
    {
        using ( BlockTableRecord blockTableRecord = (BlockTableRecord)transaction.GetObject( blockTable[ BlockTableRecord.ModelSpace ], OpenMode.ForWrite ) )
        {
            // полилиния инициализируется первым участком
            Entity polyline = splitEntities[ 0 ];

            polyline.SetDatabaseDefaults();
            polyline.ColorIndex = 3;

            // из коллекции учасков первый исключается - он уже использован
            splitEntities.RemoveAt( 0 );

            if ( splitEntities.Count > 0 )
            {
                // объединение участков кривых обратно в одну полилинию
                polyline.JoinEntities( splitEntities.ToArray() );
            }

            blockTableRecord.AppendEntity( polyline );

            transaction.AddNewlyCreatedDBObject( polyline, true );
        }
    }
}

Re: Объединение линий в одну полилинию

Ну и отлично!

Сообщения 12

Тему читают: 1 гость

Страницы 1

Чтобы отправить ответ, вы должны войти или зарегистрироваться

Форумы CADUser → Программирование → .NET → Объединение линий в одну полилинию