Касательные

Автор Тема: Касательные  (Прочитано 4435 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн alshАвтор темы

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Касательные
« : 10-05-2023, 10:26:06 »
Всем добрый день.
Может кто-то сталкивался с необходимостью получить окружность касательную к 2 другим непересекающимся окружностям и линии?
Это задача Аполлония круг круг линия (circle circle line CCL)
https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%90%D0%BF%D0%BE%D0%BB%D0%BB%D0%BE%D0%BD%D0%B8%D1%8F
Хотелось бы код конечно но устроит и геометрическое решение или ссылка на него
спасибо

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 533
  • Карма: 117
Re: Касательные
« Ответ #1 : 10-05-2023, 12:00:42 »
Всем добрый день.
Может кто-то сталкивался с необходимостью получить окружность касательную к 2 другим непересекающимся окружностям и линии?
Это задача Аполлония круг круг линия (circle circle line CCL)
https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%90%D0%BF%D0%BE%D0%BB%D0%BB%D0%BE%D0%BD%D0%B8%D1%8F
Хотелось бы код конечно но устроит и геометрическое решение или ссылка на него
спасибо

Готового варианта не знаю.
Судя по описанию нужно рассмотреть 4 варианта.
Можно составить систему(ы) уравнений и получить координаты.

Окружность
https://ru.wikipedia.org/wiki/%D0%9E%D0%BA%D1%80%D1%83%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D1%8C

Прямая
https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D1%8F%D0%BC%D0%B0%D1%8F

Перпендикулярность
https://ru.wikipedia.org/wiki/%D0%9F%D0%B5%D1%80%D0%BF%D0%B5%D0%BD%D0%B4%D0%B8%D0%BA%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D0%BE%D1%81%D1%82%D1%8C

Оффлайн alz

  • ADN OPEN
  • **
  • Сообщений: 92
  • Карма: 11
Re: Касательные
« Ответ #2 : 10-05-2023, 21:28:00 »
в целом есть встроенная команда в автокаде на создание такой окружности, и от нефиг делать набросал такой код, вроде строит но есть неоднозначности, то есть в некоторых случаях исходные круги могут оказаться внутри окружности, так как касательные могут проходить с двух сторон круга и непонятная фигня с использованием ed.command() если по время работы команды двигать мышкой, то отправка координат сбивается, так что она прекрасно работает если выбрать объекты и не трогая мышь нажать интер.

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. using System;
  7. using System.Collections.Generic;
  8.  
  9.  
  10.  
  11. namespace Function
  12. {
  13.     public class Class1
  14.     {
  15.         [CommandMethod("ttest1")]
  16.         public void test()
  17.         {
  18.             List<ObjectId> ids = GetObjectsIds(new List<string> { "CIRCLE,LINE"});
  19.             if (ids.Count != 3) return;
  20.             Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  21.             Editor ed = doc.Editor;        
  22.             using (Transaction tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
  23.             {
  24.                 //создаем 3 переменные
  25.                 Line line = null;
  26.                 Circle c1 = null;
  27.                 Circle c2 = null;
  28.                 //заполняем переменные
  29.                 foreach (ObjectId id in ids)
  30.                 {
  31.                     Object obj = tr.GetObject(id, OpenMode.ForRead, false, true) as Object;
  32.                     if (obj is Line && line == null)
  33.                     {
  34.                         line = obj as Line;
  35.                         continue;
  36.                     }
  37.                     if (obj is Circle)
  38.                     {
  39.                         if (c1 == null)
  40.                         {
  41.                             c1 = obj as Circle;
  42.                             continue;
  43.                         };
  44.                         if (c2 == null) c2 = obj as Circle;
  45.                     }
  46.                 }
  47.                 //если выбрано 2 круга и линия продолжаем
  48.                 if (line != null && c1 != null && c2 != null && c1.Radius > 0 && c2.Radius > 0)
  49.                 {
  50.                     //проверяем элементы на пересечения
  51.                     using (Point3dCollection collection = new Point3dCollection())
  52.                     {
  53.                         c1.IntersectWith(c2, Intersect.OnBothOperands, collection, IntPtr.Zero, IntPtr.Zero);
  54.                         if (collection.Count > 0)
  55.                         {
  56.                             tr.Abort();
  57.                             return;
  58.                         }
  59.                         collection.Clear();
  60.                         c1.IntersectWith(line, Intersect.OnBothOperands, collection, IntPtr.Zero, IntPtr.Zero);
  61.                         if (collection.Count > 0)
  62.                         {
  63.                             tr.Abort();
  64.                             return;
  65.                         }
  66.                         collection.Clear();
  67.                         c2.IntersectWith(line, Intersect.OnBothOperands, collection, IntPtr.Zero, IntPtr.Zero);
  68.                         if (collection.Count > 0)
  69.                         {
  70.                             tr.Abort();
  71.                             return;
  72.                         }
  73.                     }
  74.                     //проверяем что круги с одной стороны от линии
  75.                     if ((line.GetClosestPointTo(c1.Center, true) - c1.Center).GetNormal() ==
  76.                         (line.GetClosestPointTo(c2.Center, true) - c2.Center).GetNormal())
  77.                     {
  78.                         //получаем 3 точки примерного положеня касательных
  79.                         Point3d p1 = line.GetClosestPointTo(c1.Center, true) + (line.GetClosestPointTo(c2.Center, true) - line.GetClosestPointTo(c1.Center, true)) * 0.5;
  80.                         Point3d p2 = c1.Center + (p1 - c1.Center).GetNormal() * c1.Radius;
  81.                         Point3d p3 = c2.Center + (p1 - c2.Center).GetNormal() * c2.Radius;                        
  82.                         //просим мудрую машину построить нам круг)))
  83.                         ed.Command("._Circle", "_3p", "_tan", p1, "_tan", p2, "_tan", p3);
  84.                     }
  85.                 }
  86.                 tr.Commit();
  87.             }            
  88.         }
  89.         private List<ObjectId> GetObjectsIds(List<string> objectTypes)
  90.         {
  91.             //создаем результат выбора
  92.             PromptSelectionResult pResult;
  93.             //создаем список Id
  94.             List<ObjectId> result = new List<ObjectId>();
  95.             if (objectTypes != null && objectTypes.Count > 0)
  96.             {
  97.                 //создаем строку с типами объектов для фильтра
  98.                 string objectTypesAll = string.Empty;
  99.                 foreach (string objectType in objectTypes) objectTypesAll = objectTypesAll + objectType + ",";
  100.                 objectTypesAll = objectTypesAll.Substring(0, objectTypesAll.Length - 1);
  101.                 pResult = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.GetSelection(
  102.                     new SelectionFilter(new TypedValue[] { new TypedValue((int)DxfCode.Start, objectTypesAll) }));
  103.             }
  104.             else
  105.             {
  106.                 pResult = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.GetSelection();
  107.             }
  108.             //записываем Id выбранных объектов в список и возвращаем его
  109.             if (pResult.Status == PromptStatus.OK) result.AddRange(pResult.Value.GetObjectIds());
  110.             return result;
  111.         }
  112.     }
  113. }


Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Re: Касательные
« Ответ #3 : 11-05-2023, 07:53:52 »
Построение окружности по касательным - это та же самая задача, что и построение скругления. Эту задачку я решал несколько месяцев. Результат тут: https://sites.google.com/site/avcplugins/fillet
Теоретически звучит просто: офсетим обе curve (дуги или линии) между которыми строим дугу скругления на радиус скругления, находим их пересечение - это центр новой дуги. затем проецируем эту точку перпендикулярно на обе curve - это будут две конечные точки дуги-скругления, точки касания.
На практике это куева хуча вариантов алгоритма и 100500 разных проверок. Только пересечение двух дуг дает 4 варианта скруглений, для построения которых надо использовать 3 разных алгоритма (внутрь двух дуг, наружу двух дуг, наружу + внутрь). А еще скругление может быть и между не пересекающимися окружностями (два варианта - для вложенных окружностей и невложенных), пересечения линий, пересечения линий и дуг... В общем это порядка 2000 строк кода только основных функций вычисления трех точек дуги. И еще овердофига вспомогательных методов и хелперов. Пришлось вспомнить всю школьную тригонометрию и стереометрию и переписывать на чистой математике многие функции API из-за их тормознутости и глюков.... Возможно профессор математики придумал бы что-то и по проще :))

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: Касательные
« Ответ #4 : 11-05-2023, 18:55:17 »
В частном случае, если требуется только одна окружность, которая самая маленькая, можно определить её методом поиска с заданной точностью. Один из вариантов:
1. Строим перпендикуляры из центров окружностей на линию. Находим ближайшие точки окружностей и линии.
2. Определяем точку пересечения отрезков, построенных по ближайшим точкам крест-накрест.
3. Находим расстояния от точки пересечения до линии и окружностей.
4. Находим наибольшее из них - будет использоваться для определения направления перемещения. Величину перемещения вычисляем, например, как половина от разности наибольшего и наименьшего расстояния. Перемещаем точку.
5. Повторяем пункты 3-4, пока расстояния не окажутся равными в пределах заданного допуска.
6. Профит.

Оффлайн alz

  • ADN OPEN
  • **
  • Сообщений: 92
  • Карма: 11
Re: Касательные
« Ответ #5 : 11-05-2023, 19:01:46 »
В частном случае, если требуется только одна окружность, которая самая маленькая, можно определить её методом поиска с заданной точностью. Один из вариантов:
1. Строим перпендикуляры из центров окружностей на линию. Находим ближайшие точки окружностей и линии.
2. Определяем точку пересечения отрезков, построенных по ближайшим точкам крест-накрест.
3. Находим расстояния от точки пересечения до линии и окружностей.
4. Находим наибольшее из них - будет использоваться для определения направления перемещения. Величину перемещения вычисляем, например, как половина от разности наибольшего и наименьшего расстояния. Перемещаем точку.
Повторяем пункты 3-4, пока расстояния не окажутся равными в пределах заданного допуска.
Профит.

Я думал над таким вариантом, но сразу уперся в первый же случай когда 2 круга разного радиуса на одном и том же перпендикуляре, в этом случае метод сразу становится бесконечно зацикленным) и имеет 2 равноценных решения

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: Касательные
« Ответ #6 : 11-05-2023, 19:04:07 »
уперся в первый же случай когда 2 круга разного радиуса на одном и том же перпендикуляре, в этом случае метод сразу становится бесконечно зацикленным
Не понимаю, почему поиск зациклится?

Оффлайн alz

  • ADN OPEN
  • **
  • Сообщений: 92
  • Карма: 11
Re: Касательные
« Ответ #7 : 11-05-2023, 19:29:41 »
Не понимаю, почему поиск зациклится?

вдоль перпендикуляра хоть куда двигай на центр не выйдешь


Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: Касательные
« Ответ #8 : 11-05-2023, 19:47:53 »
А, ну да, в этом случае не подойдёт такой алгоритм. Да, он сильно не универсальный и у него есть ещё ограничения. Например, если расстояние между окружностями будет сильно больше, чем расстояние до линии.

Оффлайн alshАвтор темы

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Re: Касательные
« Ответ #9 : 12-05-2023, 00:57:19 »
После долгих поисков в интернете нашел интересную публкацию  (на английском конечно, по русски ничего нет) где пишется что решение в методе инверсии. из CCL можно упростить в  CLP но как это решить с инверсией - непонятно












Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 533
  • Карма: 117
Re: Касательные
« Ответ #10 : 12-05-2023, 14:55:52 »
Это задача Аполлония круг круг линия (circle circle line CCL)
А точно это задача Аполлония?
У него рассмотрены различные варианты касания, внутренние и внешние.
Обсуждается только один вариант когда круг "вписан" между объектами.

Если так, может проще построить в автокаде, воспользоваться командным методом и считать координаты, как написал alz:

Круг, 3 точки касания
Построение круга, касательного к трем объектам
^C^C_circle _3p _tan \_tan \_tan \

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: Касательные
« Ответ #11 : 12-05-2023, 15:23:53 »
Построение круга, касательного к трем объектам
^C^C_circle _3p _tan \_tan \_tan \
Кстати, может этот метод как раз тоже самое делает: https://help.autodesk.com/view/OARX/2021/ENU/?guid=OARX-ManagedRefGuide-Autodesk_AutoCAD_Geometry_CircularArc2d_Set_Curve2d_Curve2d_Curve2d_double_double_double
Но только с объектами Geometry, конечно же

Оффлайн alz

  • ADN OPEN
  • **
  • Сообщений: 92
  • Карма: 11
Re: Касательные
« Ответ #12 : 13-05-2023, 09:29:21 »
Кстати, может этот метод как раз тоже самое делает: https://help.autodesk.com/view/OARX/2021/ENU/?guid=OARX-ManagedRefGuide-Autodesk_AutoCAD_Geometry_CircularArc2d_Set_Curve2d_Curve2d_Curve2d_double_double_double
Но только с объектами Geometry, конечно же

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


Код - C# [Выбрать]
  1.  Point2d nc = new Point2d((p1.X + p2.X + p3.X) / 3, (p1.Y + p2.Y + p3.Y) / 3);
  2. using (CircularArc2d arc2D = new CircularArc2d(nc, nc.GetDistanceTo(p1.GetPoint2d())))
  3. {                                
  4.     Curve2d line2d = new LineSegment2d(line.StartPoint.GetPoint2d(), line.EndPoint.GetPoint2d()) as Curve2d;
  5.     Curve2d c12d = new CircularArc2d(c1.Center.GetPoint2d(), c1.Radius) as Curve2d;
  6.     Curve2d c22d = new CircularArc2d(c2.Center.GetPoint2d(), c2.Radius) as Curve2d;
  7.     arc2D.Set(line2d, c12d, c22d, line2d.GetParameterOf(p1.GetPoint2d()), c12d.GetParameterOf(p2.GetPoint2d()), c22d.GetParameterOf(p3.GetPoint2d()));
  8.     Circle ccc = new Circle(new Point3d(new Plane(), arc2D.Center), Vector3d.ZAxis, arc2D.Radius);
  9.     using (BlockTableRecord ms = tr.GetObject(HostApplicationServices.WorkingDatabase.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord)
  10.     {                                  
  11.         ms.AppendEntity(ccc);
  12.         tr.AddNewlyCreatedDBObject(ccc, true);
  13.     }
  14. }




Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: Касательные
« Ответ #13 : 13-05-2023, 12:05:56 »
Я тоже не понимаю как он работает. Описания внятного нет ни в .NET документации, ни в ObjectARX. Непонятно - что за параметры передаются? Если это должны быть значения параметров в точках касания, то метод, по сути, бесполезен: можно вычислить положения точек по значениям параметров и построить окружность по этим трём точкам. А нам бы как-то сперва вычислить бы эти точки. Беглый поиск в гугле тоже не помог, примеров использования не нашёл.

Оффлайн Lemieux

  • ADN OPEN
  • ****
  • Сообщений: 379
  • Карма: 21
Re: Касательные
« Ответ #14 : 13-05-2023, 12:07:47 »
Вот вроде человек решил задачу и можно скачать файл https://www.cadtutor.net/forum/files/file/29-apollonius-problem-solvedlsp/