Сохранение зависимого положения точки. И снова вектора

Автор Тема: Сохранение зависимого положения точки. И снова вектора  (Прочитано 4187 раз)

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

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Всем привет! Тема из разряда "Помогите! Сам не соображу"  :D
Как только вопрос касается векторов, то у меня что-то не получается
Итак, имеются три точки: p1, p2, p3. Координаты их известны:



Задача стоит в том, чтобы при изменении положения точек они менялись по определенной зависимости:
1. Если я передвигаю точку p3, то точки p1 и p2 не меняются
2. Если я меняю точку p1 или p2, то точка p3 должна остаться в том же положении относительно вектора (p2-p1)

Типа вот того - подвинул точку р2 и точка р3 подвинулась тоже, но сохранила относительное исходное положение:



Предположим, что точка р1 - это всегда начало координат (0,0,0). Тогда мне нужно получить единичный вектор между точками р2 и р2 - (р2-р1).GetNormal(). Получить вектор от точки р3 до р2 и дальше... Вот дальше у меня что-то не получается ))

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Не вполне понял что ты хочешь, но догадываюсь, что тебе нужна трансформация по матрице поворота относительно точки P1, на угол, на который повернулся [P1;P2]. Если же нужно учесть изменение расстояния [P1;P2], то потребуется ещё и операция масштабирования.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Александр Ривилис, ну вот почти, но я хочу обойтись без матрицы. Мне кажется, что отношения точки р3 к точке р2 достаточно - остальное все высчитать "по месту"
Попробую на примере. Может сам смогу понять  :D
Вот пример:



Первоначальное состояние
Точка р1 с координатами (0,20). Я координаты все буду писать без z, так как это значение не важно для задачи
Точка р2 с координатами (0,10)
Точка р3 с координатами (5,5)
Значит единичный вектор р2-р1 будет равняться (0,-1). А то самое отношение точки р3 к точке р2 равняется (+5,-5) - т.е. к X прибавить 5, а от Y отнять 5.

Новое состояние - я перемещаю точку р2 в новое положение (в общем-то я повернул ее на 90 градусов)
Точка р1 осталась с координатами (0,20)
Точка р2 стала с координатами (10,20). Но отношение точки р3 к точке р2 не изменилось (+5,-5) - изменился только вектор р2-р1.
Т.е. точка р3 относительно точки р2 должна остаться в том же положении

Вот не могу понять что на что нужно умножать и что с чем складывать

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
ну вот почти, но я хочу обойтись без матрицы.
Зря. Тем более, что все эти операции есть в Matrix3d.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Зря. Тем более, что все эти операции есть в Matrix3d.
Я ей пользоваться не умею  :-[

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я совсем (!!!) не тестировал, но должно быть что-то похожее:
Код - C# [Выбрать]
  1. Point2d Align3Point(Point2d p1, Point2d p2, Point2d p3, Point2d p2_new)
  2. {
  3.   Point2d p;
  4.   Vector2d v = p2 - p1;
  5.   Vector2d v_new = p2_new - p1;
  6.   double ang = v.GetAngleTo(v_new); // Угол поворота
  7.   double scale = v_new.Length / v.Length; // Масштаб
  8.   Matrix2d matRot = Matrix2d.Rotation(ang, p1); // Матрица поворота
  9.   Matrix2d matScale = Matrix2d.Scaling(scale, p1); // Матрица масштабирования
  10.   p = p3;
  11.   p = p.TransformBy(matScale);
  12.   p = p.TransformBy(matRot);
  13.   return p;
  14. }
Возможно нужно поменять порядок трансформаций или угол с противоположным знаком. Но идея видна.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Вот это уже немного протестировано:
Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.EditorInput;
  7.  
  8. [assembly: CommandClass(typeof(RotateAndScale.MyCommands))]
  9.  
  10. #pragma warning disable 0618
  11.  
  12. namespace RotateAndScale
  13. {
  14.  
  15.   public class MyCommands
  16.   {
  17.     [CommandMethod("TRS")]
  18.     public void Trs()
  19.     {
  20.       // Put your command code here
  21.       Document doc = Application.DocumentManager.MdiActiveDocument;
  22.       if (doc == null) return;
  23.       Editor ed = doc.Editor;
  24.       Point3d p1, p2, p3, p2_new, p3_new;
  25.       PromptPointOptions pr = new PromptPointOptions("");
  26.       pr.Message = "\nУкажите точку p1: ";
  27.       PromptPointResult rs = ed.GetPoint(pr);
  28.       if (rs.Status != PromptStatus.OK) return;
  29.       p1 = rs.Value;
  30.       pr.Message = "\nУкажите точку p2: ";
  31.       pr.UseBasePoint = true; pr.BasePoint = p1;
  32.       rs = ed.GetPoint(pr);
  33.       if (rs.Status != PromptStatus.OK) return;
  34.       p2 = rs.Value;
  35.       pr.Message = "\nУкажите точку p3: ";
  36.       pr.UseBasePoint = true; pr.BasePoint = p2;
  37.       rs = ed.GetPoint(pr);
  38.       if (rs.Status != PromptStatus.OK) return;
  39.       p3 = rs.Value;
  40.       ObjectId idPoly = ObjectId.Null;
  41.       using (BlockTableRecord curSpace = doc.Database.CurrentSpaceId.Open(OpenMode.ForWrite) as BlockTableRecord)
  42.       {
  43.         using (Polyline pline = new Polyline(3))
  44.         {
  45.           pline.AddVertexAt(0, new Point2d(p1.X, p1.Y), 0,0,0);
  46.           pline.AddVertexAt(1, new Point2d(p2.X, p2.Y), 0, 0, 0);
  47.           pline.AddVertexAt(2, new Point2d(p3.X, p3.Y), 0, 0, 0);
  48.           idPoly = curSpace.AppendEntity(pline);
  49.         }
  50.       }
  51.       pr.Message = "\nУкажите точку p2_new: ";
  52.       pr.UseBasePoint = true; pr.BasePoint = p1;
  53.       rs = ed.GetPoint(pr);
  54.       if (rs.Status != PromptStatus.OK) return;
  55.       p2_new = rs.Value;
  56.       p3_new = Align3Point(p1, p2, p3, p2_new);
  57.       using (Polyline pline = idPoly.Open(OpenMode.ForRead) as Polyline)
  58.       using (Polyline pline_new = pline.Clone() as Polyline)
  59.       using (BlockTableRecord curSpace = doc.Database.CurrentSpaceId.Open(OpenMode.ForWrite) as BlockTableRecord)
  60.       {
  61.         pline_new.SetPointAt(1, new Point2d(p2_new.X, p2_new.Y));
  62.         pline_new.SetPointAt(2, new Point2d(p3_new.X, p3_new.Y));
  63.         curSpace.AppendEntity(pline_new);
  64.       }
  65.     }
  66.  
  67.     Point3d Align3Point(Point3d p1, Point3d p2, Point3d p3, Point3d p2_new)
  68.     {
  69.       Point3d p;
  70.       Vector3d v = p2 - p1;
  71.       Vector3d v_new = p2_new - p1;
  72.       double ang = v.GetAngleTo(v_new,Vector3d.ZAxis); // Угол поворота
  73.       double scale = v_new.Length / v.Length; // Масштаб
  74.       Matrix3d matRot = Matrix3d.Rotation(ang, Vector3d.ZAxis, p1); // Матрица поворота
  75.       Matrix3d matScale = Matrix3d.Scaling(scale, p1); // Матрица масштабирования
  76.       p = p3;
  77.       p = p.TransformBy(matRot);
  78.       p = p.TransformBy(matScale);
  79.       return p;
  80.     }
  81.   }
  82. }

Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение Александр Пекшев aka Modis 22-10-2017, 22:44:28

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Александр Ривилис, спасибо. Но мне коллега подсказал другой вариант и я использовал его. По сути это одно и тоже, но его вариант мне как-то больше понравился ))
Код - C# [Выбрать]
  1. /// <summary>Вторая (конечная) точка примитива в мировой системе координат</summary>
  2. public Point3d EndPoint { get; set; } = Point3d.Origin;
  3.  
  4. public double BottomLineLength { get; set; } = 10.0;
  5. public double BottomLineAngle { get; set; } = 0.0;
  6.  
  7. private Point3d _bottomMarkerPoint3D;
  8. /// <summary>Нижняя точка расположения маркеров</summary>  
  9. public Point3d BottomMarkerPoint
  10. {
  11.     get
  12.     {
  13.         var baseVector = new Vector3d(1.0, 0.0, 0.0);
  14.         var angleA = baseVector.GetAngleTo(EndPoint - InsertionPoint, new Vector3d(0.0, 0.0, 1.0));
  15.         _bottomMarkerPoint3D = new Point3d(
  16.             EndPoint.X + BottomLineLength * Math.Cos(angleA + BottomLineAngle),
  17.             EndPoint.Y + BottomLineLength * Math.Sin(angleA + BottomLineAngle),
  18.             EndPoint.Z);
  19.         return _bottomMarkerPoint3D;
  20.     }
  21.     set
  22.     {
  23.         _bottomMarkerPoint3D = value;
  24.         BottomLineLength = (value - EndPoint).Length;
  25.         BottomLineAngle  = (EndPoint - InsertionPoint).GetAngleTo(value - EndPoint, new Vector3d(0.0, 0.0, 1.0));
  26.     }
  27. }
Правда с методом GetAngleTo я не совсем разобрался. Точнее не совсем понял как он работает, но нашел как нужно сделать ))

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
По сути это одно и тоже
Вообще-то это совершенно разные вещи. Ну и вместо new Vector3d(0.0, 0.0, 1.0) правильнее использовать Vector3d.ZAxis.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Ну и вместо new Vector3d(0.0, 0.0, 1.0) правильнее использовать Vector3d.ZAxis
Спасибо, подправлю

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Получается вроде все так, как я хотел

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Александр Ривилис, столкнулся с тем же вопросом, но уже в другом случае. Решил попробовать ваш пример и вот он не работает. Точнее работает, но неверно - точка смещается еще немного в сторону.
Использовал ваш код в своем контексте:
Код - C# [Выбрать]
  1. var vecNew = (gripPoint.GripPoint + offset - InitInsertionPoint);
  2. var angle = (InitEndPoint - InitInsertionPoint).GetAngleTo(vecNew, Vector3d.ZAxis);
  3. var scale = vecNew.Length / (InitEndPoint - InitInsertionPoint).Length;
  4. var matRot = Matrix3d.Rotation(angle, Vector3d.ZAxis, InitInsertionPoint);
  5.  
  6. var matScale = Matrix3d.Scaling(scale, InitInsertionPoint);
  7. var p = InitBottomOrientPoint;
  8. p = p.TransformBy(matRot);
  9. p = p.TransformBy(matScale);
  10.  
  11. gripPoint.Axis.BottomOrientPoint = p;

Вот пример того, как работает только поворот - все правильно:


А вот только масштабирование работает неправильно:


И как-бы вот понятно почему так происходит, но непонятно как исправить
Соответственно, поворот+масштабирование работают неверно.
Мне коллега помог сделать решение через математические вычисления, но мне интересно разобраться в варианте с матрицами

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Дело не в коде, а в векторах ручек. Сейчас, скорее всего, ручка справа опирается на точку вставки блока:

Поэтому и происходит такая трансформация вектора при масштабировании.
Нужно трансформировать другой вектор, например такой:

P.S. Хотя, дело ещё может быть в другом. В общем, нужна картинка того, какие вектора трансформируются.