Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: Radan от 20-10-2015, 15:15:48

Название: Полилинии и дуги в одну полилинию
Отправлено: Radan от 20-10-2015, 15:15:48
Необходимо объединить несколько полилиний и дугу в одну полилинию.
Пробую так:
Код - C# [Выбрать]
  1. Entity srcPLine = acTr.GetObject(idL1, OpenMode.ForRead) as Entity;
  2.                             Entity addPLine1 = acTr.GetObject(idArc, OpenMode.ForRead) as Entity;
  3.                             Entity addPLine2 = acTr.GetObject(idL2, OpenMode.ForRead) as Entity;
  4.                             srcPLine.UpgradeOpen();
  5.                             srcPLine.JoinEntity(addPLine1);
  6.  
  7.                             addPLine1.UpgradeOpen();
  8.                             addPLine1.Erase();
  9.                             addPLine2.UpgradeOpen();
  10.                             addPLine2.Erase();
  11.  

AUTOCAD 2010.
Получаю ошибку:
Error   282   'Autodesk.AutoCAD.DatabaseServices.Entity' does not contain a definition for 'JoinEntity' and no extension method 'JoinEntity' accepting a first argument of type 'Autodesk.AutoCAD.DatabaseServices.Entity' could be found (are you missing a using directive or an assembly reference?)
Подозреваю, что в 2010 автокаде  'JoinEntity' просто не реализован.
Как можно решить проблему?
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Андрей Бушман от 20-10-2015, 15:37:25
Подозреваю, что в 2010 автокаде  'JoinEntity' просто не реализован.
Похоже на то. Во всяком случае в справке он фигурирует начиная с 2012-й версии.

Как можно решить проблему?
Построить новую полилинию. Если важно, чтобы она имела хендл твоей srcPLine, то можешь затем воспользоваться методом DBObject.HandOverTo() (http://bushman-andrey.blogspot.ru/2013/01/dbobjecthandoverto-objectid-handle.html).
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Radan от 20-10-2015, 15:40:43
Построить новую полилинию не проблема, если бы объекты были только полилиниями.
Проблема в том, что часть объектов - полилиниий, а часть дуги.

Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Александр Ривилис от 20-10-2015, 16:17:43
Radan
Приветствую на форуме. Обрати внимание на то, как следует форматировать код на форуме (у меня в подписи).
Методы Entity.JontEntity и Entity.JontEntites появились в AutoCAD 2011. Очевидно, что в предыдущих версиях придётся написать собственный код. Особых проблем я с ним не вижу. В любом случае если у тебя есть для объединения Line, Arc, Polyline, то Polyline желательно сначала разбить на Line и Arc. Если есть вопросы - задавай.
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Radan от 20-10-2015, 16:19:55
Объекты у меня разбиты и идут по порядку, т.е. точка конца первого соответствует точке начала второго.
Нужен механизм объединения.
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Александр Ривилис от 20-10-2015, 16:27:47
Объекты у меня разбиты и идут по порядку, т.е. точка конца первого соответствует точке начала второго.
Тогда задача резко упрощается.
Надеюсь, что это касается и дуг и их плоскость совпадает с плоскостью остальной части полилинии.
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Radan от 20-10-2015, 16:30:58
Это элементы плоского чертежа, Z=0.
Пусть для начала будет всего 3 элемента - линия, дуга и линия.
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Дима_ от 20-10-2015, 16:37:23
А в чем затык-то - просто строй полилинию по конечным точкам, и задавай на дуговых сегментах "бублики" - где-то на dwg.ru я такое на лиспе выкладывал.
з.ы. там по моему надо было либо дуговые сегменты, либо интерполированные с заданным шагом.
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Александр Ривилис от 20-10-2015, 16:46:46
1) Создаёшь полилинию (Polyline)
2) Добавляешь ей 0-ую вершину - начальная точка отрезка с bulge = 0.0 (метод Polyline.AddVertexAt)
3) Добавляешь ей 1-ую вершину - начальная точка дуги с bulge = bulge дуги (дальше распишу алгоритм её вычисления)
4) Добавляешь ей 2-ую вершину - конечная точка дуги с bulge = 0.0
5) Добавляешь ей 3-ую вершину - конец второй линии в bulge = 0.0
Всё.

Код - C# [Выбрать]
  1. // Вычисление кривизны (bulge) дуги
  2. static double BulgeFromArc(Arc a, bool clockwise)
  3. {
  4.         double bulge = 0.0;
  5.         double newStart =
  6.             (a.StartAngle > a.EndAngle) ? (a.StartAngle - 8 * Math.Atan(1)) : (a.StartAngle);
  7.         bulge = Math.Tan((a.EndAngle - newStart) / 4);
  8.         if (clockwise) bulge = -bulge;
  9.         return bulge;
  10. }
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Александр Ривилис от 20-10-2015, 23:47:24
Я почти не тестировал, но этот код похоже решает поставленную задачу. Условия:
1) Все отрезки и дуги лежат в плоскости X0Y (т.е. Z == 0.0)
2) Концы у всех отрезков и дуг совпадают (в противном случае необходимо вводить точность при проверке на совпадение)
Код - C# [Выбрать]
  1. using System;
  2. using System.Collections;
  3. using Autodesk.AutoCAD.Runtime;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.ApplicationServices;
  6. using Autodesk.AutoCAD.EditorInput;
  7. using Autodesk.AutoCAD.Geometry;
  8.  
  9. #pragma warning disable 0618
  10.  
  11. [assembly: CommandClass(typeof(Rivilis.Contour))]
  12.  
  13. namespace Rivilis
  14. {
  15.   public class Contour
  16.   {
  17.     [CommandMethod("MakePline")]
  18.     public void MakePline()
  19.     {
  20.       Document doc = Application.DocumentManager.MdiActiveDocument;
  21.       Editor ed = doc.Editor;
  22.       Database db = doc.Database;
  23.       // Отбираем только отрезки и дуги
  24.       SelectionFilter sf =
  25.         new SelectionFilter(new TypedValue[] { new TypedValue((int)DxfCode.Start,"LINE,ARC") });
  26.       PromptSelectionResult rs = ed.GetSelection(sf);
  27.       if (rs.Status != PromptStatus.OK) return;
  28.       ObjectIdCollection ids = new ObjectIdCollection(rs.Value.GetObjectIds());
  29.       while (ids.Count > 0) {
  30.         using (Polyline p = MakeJoinedPoly(ref ids)) {
  31.           if (p != null) {
  32.             using (BlockTableRecord btr = db.CurrentSpaceId.Open(OpenMode.ForWrite) as BlockTableRecord) {
  33.               btr.AppendEntity(p);
  34.             }
  35.           }
  36.           else {
  37.             ed.WriteMessage("\nОшибка во входных данных!");
  38.             return;
  39.           }
  40.         }
  41.       }
  42.     }
  43.     public static Polyline MakeJoinedPoly(ref ObjectIdCollection ids)
  44.     {
  45.       if (ids.Count == 0) return null;
  46.       // Создаём полилинию
  47.       Polyline p = new Polyline();
  48.         p.SetDatabaseDefaults();
  49.         ObjectId idOwn = ObjectId.Null;
  50.         ObjectId idFirst = ids[0];
  51.         Point3d nextPt = Point3d.Origin;
  52.         Point3d prevPt = Point3d.Origin;
  53.         // Добавляем первые две вершины из первого выбранного примитива
  54.         using (Curve c = idFirst.Open(OpenMode.ForRead) as Curve) {
  55.           p.AddVertexAt(0, ToPoint2d(c.StartPoint), BulgeFromArc(c, false), 0, 0);
  56.           p.AddVertexAt(1, ToPoint2d(c.EndPoint), 0, 0, 0);
  57.           nextPt = c.EndPoint;
  58.           prevPt = c.StartPoint;
  59.           idOwn = c.OwnerId;
  60.         }
  61.        
  62.         ids.Remove(idFirst);
  63.  
  64.         int prevCnt = ids.Count + 1;
  65.  
  66.         while (ids.Count > 0 && ids.Count < prevCnt)
  67.         {
  68.           prevCnt = ids.Count;
  69.           foreach (ObjectId id in ids) {
  70.             using (Curve cv = id.Open(OpenMode.ForRead) as Curve) {
  71.               if (cv.StartPoint == nextPt || cv.EndPoint == nextPt) {
  72.                 double bulge = BulgeFromArc(cv, cv.EndPoint == nextPt);
  73.                 p.SetBulgeAt(p.NumberOfVertices - 1, bulge);
  74.                 if (cv.StartPoint == nextPt)
  75.                   nextPt = cv.EndPoint;
  76.                 else
  77.                   nextPt = cv.StartPoint;
  78.                 p.AddVertexAt(p.NumberOfVertices, ToPoint2d(nextPt), 0, 0, 0);
  79.                 ids.Remove(id);
  80.                 break;
  81.               } else if (cv.StartPoint == prevPt || cv.EndPoint == prevPt) {
  82.                 double bulge = BulgeFromArc(cv, cv.StartPoint == prevPt);
  83.                 if (cv.StartPoint == prevPt)
  84.                   prevPt = cv.EndPoint;
  85.                 else
  86.                   prevPt = cv.StartPoint;
  87.                 p.AddVertexAt(0, ToPoint2d(prevPt), bulge, 0, 0);
  88.                 ids.Remove(id);
  89.                 break;
  90.               }
  91.             }
  92.           }
  93.         }
  94.         if (p.NumberOfVertices == 0)
  95.           return null;
  96.         else  
  97.           return p;
  98.     }
  99.     // Функция возвращает кривизну дуги (bulge) или 0.0
  100.     static double BulgeFromArc(Curve c, bool clockwise)
  101.     {
  102.       double bulge = 0.0;
  103.       Arc a = c as Arc;
  104.       if (a == null) return bulge;
  105.       double newStart = (a.StartAngle > a.EndAngle) ?
  106.         (a.StartAngle - 8 * Math.Atan(1)) : (a.StartAngle);
  107.       bulge = Math.Tan((a.EndAngle - newStart) / 4);
  108.       if (clockwise) bulge = -bulge;
  109.       return bulge;
  110.     }
  111.     // Функция преобразует Point3d в Point2d (отбрасывает Z)
  112.     static Point2d ToPoint2d(Point3d p) {
  113.       return new Point2d(p.X, p.Y);
  114.     }
  115.   }
  116. }
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Radan от 21-10-2015, 08:46:17
Спасибо, Александр!
Код рабочий, только добавил удаление отрезков и дуг.
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Александр Ривилис от 21-10-2015, 08:54:00
Отлично. Задача была несложной, но пару нюансов возникло. Например, путаница с началом и концом дугового сегмента - при расчленении полилинии с дугами они частенько путаются.
Название: Re: Полилинии и дуги в одну полилинию
Отправлено: Александр Ривилис от 22-10-2015, 16:22:01
Добавил еще и код для чистого ObjectARX (C++):  Как объединить отрезки и дуги в полилинию? (http://adn-cis.org/kak-obedinit-otrezki-i-dugi-v-poliliniyu.html)