Получение плоского изображения из 3D тела с помощью .NET.

Автор Тема: Получение плоского изображения из 3D тела с помощью .NET.  (Прочитано 18394 раз)

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

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Но если есть скругления, то при взрыве они теряются. Остаются только окружности оснований, по которым их не восстановить.
Попробуй конвертацию в SubDMesh при помощи SubDMesh.GetObjectMesh
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 822
  • Карма: 166
    • Мои плагины к Автокаду
Но если есть скругления, то при взрыве они теряются
Конечно. Это называется силуэты. Секущая выдает их отдельным массивом. Взрыв только для кубиков. Можно, кстати, легко проверить - если после взрыва нет ни одной кривой, только прямые линии, то и силуэтов точно нет.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Хотя.... можно попробовать Slice. Потом взорвать отрезанный кусок солида и выбрать кривые на плоскости сечения. Получим именно сечение (не разрез)
Да! Это то что нужно! Спасибо!
Вот видео:
« Последнее редактирование: 18-12-2018, 11:02:40 от Дмитрий Загорулькин »

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 822
  • Карма: 166
    • Мои плагины к Автокаду
Судя по картинке - это все-таки секущая плоскость задействована, а не Slice

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Slice с последующим Explode и проекцией полученных кривых на плоскость.

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 822
  • Карма: 166
    • Мои плагины к Автокаду
Slice с последующим Explode и проекцией полученных кривых на плоскость.
А, я понял. Чисто случайно выглядит как полноценный слепок. Но это просто вам повезло с телом и секущей. В большинстве случаев силуэты этим методом не получить. Только для симметричных тел при сечении по плоскости симметрии.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Хм... Похоже, что я просто изобретаю велосипед. С помощью сечений всё получается гораздо проще - оказывается, сечение и рассекаемый объект не обязательно добавлять в базу данных, чтобы использовать. Но есть ложка дёгтя. Метод Section.GenerateSectionGeometry - это просто дичь какая-то! Описание параметров не совпадает с названиями. Для сравнения - описание из ObjectARX
Пока ещё экспериментирую, но, похоже, что и распределяет полученные объекты этот метод не всегда корректно.
FurveTangency - это вообще что-то непонятное... Искажённое CurveTangency из оригинала?


Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 822
  • Карма: 166
    • Мои плагины к Автокаду
это просто дичь какая-то!
Полностью согласен. Без танцев с бубном не подходить. Было бы хоть какое-то API для проецирования поверхностей на плоскость, можно было бы силуэты получать... но увы...

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Как-то криво работает это метод Section.GenerateSectionGeometry. Упорно не хочет выдавать правильно контуры тела до плоскости сечения. То совсем их не выдаёт, то какие-то куски. Может я что-то не так делаю?
Код:
Код - 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;
  8. using System.Linq;
  9.  
  10. namespace AcadTest
  11. {
  12.     public class FlatSolidTest
  13.     {
  14.         [CommandMethod("FlatSolidTestRun")]
  15.         public void RunCmd()
  16.         {
  17.             SupportMethods.InitializeVars(out Document adoc, out Editor ed, out Database db);
  18.             if (SupportMethods.SelectEntity<Solid3d>(ed, out ObjectId id)
  19.                 && SupportMethods.GetPoint(ed, out Point3d pt, "\nSection base point: ")
  20.                 && SupportMethods.GetNextPoint(ed, pt, out Point3d secondPt, "\nSecond section point: ")
  21.                 && SupportMethods.GetPoint(ed, out Point3d forInsPt, "\nForeground objects position: ")
  22.                 && SupportMethods.GetNextPoint(ed, forInsPt, out Point3d viewInsPt, "\nBackground objects position: ")
  23.                 && SupportMethods.GetNextPoint(ed, viewInsPt, out Point3d intersInsPt, "\nIntersection objects position: "))
  24.             {
  25.                 Vector3d viewDir;
  26.  
  27.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  28.                 {
  29.                     BlockTableRecord space = tr.GetObject
  30.                             (db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  31.                     Solid3d solid = tr.GetObject(id, OpenMode.ForRead) as Solid3d;
  32.  
  33.                     GetSectionEntities
  34.                         (tr,
  35.                         solid,
  36.                         pt,
  37.                         secondPt,
  38.                         Vector3d.ZAxis,
  39.                         true,
  40.                         0.5,
  41.                         out Entity[] forEnts,
  42.                         out Entity[] backEnts,
  43.                         out Entity[] intersEnts,
  44.                         out viewDir);
  45.  
  46.                     void AddCol(Entity[] col, short colorIndex, Point3d pos)
  47.                     {
  48.                         Matrix3d move = Matrix3d.Displacement(pt.GetVectorTo(pos));
  49.                         foreach (Entity ent in col)
  50.                         {
  51.                             ent.TransformBy(move);
  52.                             ent.ColorIndex = colorIndex;
  53.                             space.AppendEntity(ent);
  54.                             tr.AddNewlyCreatedDBObject(ent, true);
  55.                         }
  56.                     }
  57.  
  58.                     AddCol(forEnts, 3, forInsPt);
  59.                     AddCol(backEnts, 4, viewInsPt);
  60.                     AddCol(intersEnts, 1, intersInsPt);
  61.  
  62.                     tr.Commit();
  63.                 }
  64.  
  65.                 ed.WriteMessage("\nSection view direction: {0:0.00}, {1:0.00}, {2:0.00}", viewDir.X, viewDir.Y, viewDir.Z);
  66.             }
  67.         }
  68.  
  69.         /// <summary>
  70.         /// Получение объектов сечения солида
  71.         /// </summary>
  72.         /// <param name="solid"></param>
  73.         /// <param name="basePoint"></param>
  74.         /// <param name="vertDir"></param>
  75.         /// <param name="viewDir"></param>
  76.         /// <param name="backEnts"></param>
  77.         /// <param name="intersEnts"></param>
  78.         public static void GetSectionEntities
  79.             (Transaction tr,
  80.             Solid3d solid,
  81.             Point3d basePoint,
  82.             Point3d secondPoint,
  83.             Vector3d vertDir, bool convertSplines,
  84.             double maxSegmentLen,
  85.             out Entity[] forEnts,
  86.             out Entity[] backEnts,
  87.             out Entity[] intersEnts,
  88.             out Vector3d viewDirection)
  89.         {
  90.             Point3dCollection pts = new Point3dCollection
  91.                 {
  92.                     basePoint,
  93.                     secondPoint
  94.                 };
  95.  
  96.             Section sec = new Section(pts, vertDir);          
  97.             viewDirection = sec.ViewingDirection;
  98.             BlockTableRecord space = tr.GetObject
  99.                 (solid.Database.CurrentSpaceId, OpenMode.ForWrite)
  100.                 as BlockTableRecord;
  101.             space.AppendEntity(sec);
  102.             tr.AddNewlyCreatedDBObject(sec, true);
  103.             sec.State = SectionState.Plane;
  104.             sec.GenerateSectionGeometry
  105.                 (solid,
  106.                 out Array intBoundaryEnts,
  107.                 out Array intFillEnts,
  108.                 out Array backgroundEnts,
  109.                 out Array foregroundEnts,
  110.                 out Array curveTangencyEnts);
  111.  
  112.             void DisposeCollection(IEnumerable col)
  113.             {
  114.                 foreach (Entity ent in col)
  115.                 {
  116.                     ent.Dispose();
  117.                 }
  118.             }
  119.            
  120.             // Уничтожаем штриховки пересечения
  121.             DisposeCollection(intFillEnts);
  122.             // Уничтожаем линии плавного перехода кривых
  123.             DisposeCollection(curveTangencyEnts);
  124.  
  125.             //// По идее, выходной нужна именно эта коллекция
  126.             //// объектов-силуэтов перед сечением
  127.             //// Но в ней почему-то либо вовсе нет объектов,
  128.             //// либо их совсем мало - недостаточно для построения
  129.             //// вида.
  130.             forEnts = foregroundEnts.Cast<Entity>().ToArray();
  131.             // Получаем выходную коллекцию - силуэты за сечением.
  132.             backEnts = backgroundEnts.Cast<Entity>().ToArray();
  133.             // Получаем выходную коллецию - объекты, полученные
  134.             // непосредственно пересечением плоскости сечения
  135.             // с 3D-телом
  136.             intersEnts = intBoundaryEnts.Cast<Entity>().ToArray();
  137.  
  138.             if (convertSplines)
  139.             {
  140.                 // Преобразуем сплайны в полилинии
  141.                 void ConvertSplines(Entity[] col)
  142.                 {
  143.                     for (int i = 0; i < col.Length; i++)
  144.                     {
  145.                         Entity ent = col[i];
  146.                         if (ent is Spline spline)
  147.                         {
  148.                             double length
  149.                                 = spline.GetDistanceAtParameter(spline.EndParam)
  150.                                 - spline.GetDistanceAtParameter(spline.StartParam);
  151.                             uint pointsCount = (uint)Math.Max
  152.                                 (length / maxSegmentLen,
  153.                                 spline.Type == SplineType.FitPoints
  154.                                 ? spline.NumFitPoints
  155.                                 : spline.NumControlPoints);
  156.                             Curve newEnt = spline.ToPolyline(pointsCount);
  157.                             col[i] = newEnt;
  158.                             ent.Dispose();
  159.                         }
  160.                     }
  161.                 }
  162.  
  163.                 ConvertSplines(forEnts);
  164.                 ConvertSplines(backEnts);
  165.                 ConvertSplines(intersEnts);              
  166.             }
  167.         }
  168.     }
  169. }
  170.  
Вспомогательные методы:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using System;
  6.  
  7. namespace AcadTest
  8. {
  9.     internal static class SupportMethods
  10.     {
  11.         public static void InitializeVars(out Document adoc, out Editor ed, out Database db)
  12.         {
  13.             adoc = Application.DocumentManager.MdiActiveDocument;
  14.             ed = adoc.Editor;
  15.             db = adoc.Database;
  16.         }
  17.  
  18.         public static bool SelectEntity<T>
  19.             (Editor ed, out ObjectId id,
  20.             string msg = "\nSelect {0}: ", bool exactMatch = true) where T : Entity
  21.         {
  22.             Type type = typeof(T);
  23.             msg = string.Format(msg, type.Name);
  24.             PromptEntityOptions opts = new PromptEntityOptions(msg);
  25.             opts.SetRejectMessage("\nWrong select!");
  26.             opts.AddAllowedClass(typeof(T), exactMatch);
  27.             PromptEntityResult entRes = ed.GetEntity(opts);
  28.             id = entRes.ObjectId;
  29.             return entRes.Status == PromptStatus.OK;
  30.         }
  31.  
  32.         public static bool GetPoint(Editor ed, out Point3d pt, string msg = "\nSelect point: ")
  33.         {
  34.             PromptPointResult ptRes = ed.GetPoint(msg);
  35.             pt = ptRes.Value;
  36.             return ptRes.Status == PromptStatus.OK;
  37.         }
  38.  
  39.         public static bool GetNextPoint(Editor ed, Point3d basePt, out Point3d pt, string msg = "\nSelect point: ")
  40.         {
  41.             PromptPointOptions opts = new PromptPointOptions(msg);
  42.             opts.BasePoint = basePt;
  43.             opts.UseBasePoint = true;
  44.             opts.UseDashedLine = true;
  45.             PromptPointResult ptRes = ed.GetPoint(opts);
  46.             pt = ptRes.Value;
  47.             return ptRes.Status == PromptStatus.OK;
  48.         }
  49.  
  50.         public static bool GetString(Editor ed, out string input, string msg = "\nInput string value: ")
  51.         {
  52.             PromptResult stringRes = ed.GetString(msg);
  53.             input = stringRes.StringResult;
  54.             return stringRes.Status == PromptStatus.OK;
  55.         }
  56.  
  57.         public static bool GetDouble(Editor ed, out double input, string msg = "\nInput double value: ")
  58.         {
  59.             PromptDoubleResult res = ed.GetDouble(msg);
  60.             input = res.Value;
  61.             return res.Status == PromptStatus.OK;
  62.         }        
  63.  
  64.         public static bool SelectEntities(Editor ed, out ObjectId[] ents, string msg = "\nSelect objects: ")
  65.         {
  66.             PromptSelectionOptions selOpts = new PromptSelectionOptions();
  67.             selOpts.MessageForAdding = msg;
  68.             PromptSelectionResult selRes = ed.GetSelection();
  69.             if (selRes.Status == PromptStatus.OK)
  70.             {
  71.                 ents = selRes.Value.GetObjectIds();
  72.                 return true;
  73.             }
  74.             else
  75.             {
  76.                 ents = null;
  77.                 return false;
  78.             }
  79.         }
  80.     }
  81. }
  82.  
Видео, поясняющее некорректную работу метода:
« Последнее редактирование: 19-12-2018, 12:03:31 от Дмитрий Загорулькин »

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 822
  • Карма: 166
    • Мои плагины к Автокаду
Видимо не зря в приведенном мной РАБОЧЕМ коде GenerateSectionGeometry вызывается 2 раза с разными настройками сечения.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Да, действительно - если изменить настройки сечения (объект SectionSettings), то удаётся получить объекты перед сечением.
Проблема в том, что мне крайне желательно это всё сделать без добавления нового объекта в базу чертежа. А настройки задаются только для сечения, добавленного в базу. Что же, буду дальше искать.

Оффлайн Sergey Makarov

  • ADN OPEN
  • Сообщений: 36
  • Карма: 0
Ну что, Дмитрий, презентация в АП не прошла даром? ) В правильном направление движетесь … я тоже ;)

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Приветствую!
А мы там что-то про это говорили? Я не помню, если честно :)
А так - это одна из задач по разработке функционала, который я примерно с сентября пытаюсь реализовать.