Официальный форум российского программного комплекса T-FLEX PLM


Поиск  Правила 
Закрыть
Логин:
Пароль:
Забыли свой пароль?
Регистрация
Войти
 
Страницы: 1 2 След.
Путь по ребрам грани
 
Добрый день!
Строю 3д путь по ребрам грани с известным именем, но получаю в модели ссылку на 3д путь.
Код
         List<BaseCurve> EdgeCurve = new List<BaseCurve>();
         List<BaseInterval> EdgeInterval = new List<BaseInterval>();
         foreach (TFlex.Model.Model3D.BodyPart body in document.Bodies)
               {
                foreach (ModelBody Body in body.TopOperation.Geometry.Solid)
                        {
                          foreach (ModelFace face in Body.Faces)
                             {
                              if (face.Name == "Базовая_грань") //фильтр по имени грани
                               {
                                foreach (ModelEdge edge in face.Edges)
                                       {             
                                       EdgeCurve.Add(edge.Curve);
                                       EdgeInterval.Add(edge.Interval);
                                       }
                               }
                             }
                        }
                }  

    //создаю путь 
    Path3D pp = new EdgePath(document);
    pp.Name = "Path";       
    pp = Path3D.Create(document, EdgeCurve, EdgeInterval); 
 
Артем, потому что метод Path3D.Create создает объект типа ReferencePath. Для построения 3D-пути по ребрам нужно использовать класс EdgePath, просто добавляя в коллекцию ребра, например:

Код
using TFlex.Model;
using TFlex.Model.Model3D;
using TFlex.Model.Model3D.Geometry;

namespace Test
{
    public class PathBuilder
    {
        static readonly Document document = TFlex.Application.ActiveDocument;

        static public void Run()
        {
            if (document == null)
                return;

            Path3D path = null;
            
            document.BeginChanges("");

            foreach (BodyPart bp in document.Bodies)
            {
                if (!(bp.BaseOperation is Block block))
                    continue;

                if ((path = BlockProcessing(block, "Грань_1")) != null)
                    break;
            }

            if (path == null)
                document.CancelChanges();
            else
                document.EndChanges();
        }

        static private EdgePath BlockProcessing(Block block, string faceName)
        {
            foreach (ModelBody body in block.Geometry.Solid)
            {
                foreach (ModelFace face in body.Faces)
                {
                    if (face.Name == faceName)
                    {
                        EdgePath path = new EdgePath(document);

                        foreach (ModelEdge edge in face.Edges)
                        {
                            path.Edges.Add(edge);
                        }

                        return path.Edges.Length > 0 ? path : null;
                    }
                }
            }

            return null;
        }
    }
}
Изменено: vite - 04.02.2021 16:32:00
T-FLEX CAD 17.1.6.0
 
Благодарю за пример.
Нашел в коде несколько недочетов, поправил, проверил - РАБОТАЕТ!
Исправленный код под спойлером.

Исправленный код
 
Цитата
Артем написал:
Нашел в коде несколько недочетов, поправил, проверил - РАБОТАЕТ!
эта проблема связана с редактором макросов. Я все тесты создаю в Visual Studio, а в макросе делаю только вызов метода Run().

Вашу задачу можно решить по селектору, чтобы каждый раз не вводить наименование грани, например:
Код
using System.Windows.Forms;
using TFlex.Model;
using TFlex.Model.Model3D;
using TFlex.Model.Model3D.Geometry;

namespace Test
{
    public class PathBuilder
    {
        static readonly Document document = TFlex.Application.ActiveDocument;

        static public void Run()
        {
            if (document == null)
                return;


            var objects = document.Selection.GetAllObjects();
            if (objects.Length == 0)
            {
                MessageBox.Show("Перед запуском макроса, необходимо выбрать грань!", "T-FLEX CAD");
                return;
            }

            foreach (var obj in objects)
            {
                if (obj.GroupType != ObjectType.Topol)
                    continue;

                var face = ((TopolReference)obj).Topol as ModelFace;
                if (face == null)
                    continue;

                CreatePath(face);
            }
        }

        static private void CreatePath(ModelFace face)
        {
            document.Diagnostics.RemoveAll();
            document.BeginChanges("");

            EdgePath path = new EdgePath(document);

            foreach (ModelEdge edge in face.Edges)
                path.Edges.Add(edge);

            document.EndChanges();
            document.Diagnostics.Add(new DiagnosticsMessage(
                DiagnosticsMessageType.Information, 
                string.Format("Create Path3D [id: {0}, name: {1}]", 
                path.ObjectId, 
                path.Name)));
        }
    }
}
Изменено: vite - 05.02.2021 12:10:41
T-FLEX CAD 17.1.6.0
 
Благодарю за еще один пример.
Суть моей задачи: необходимо собирать длины отрезков периметра грани, на которой располагается адаптивный фрагмент в сборке, эти значения обрабатывать, результат заносить в структуру фрагмента. Периметр стандартными средствами получить - не проблема, но нужны именно длины ребер. При чем их количество и геометрия вариативны в широком диапазоне. После добавления в сборку следующего адаптивного фрагмента он не пересчитывается.
 
Артем, формально можно получить практически любые данные из модели фрагмента штатными средствами T-FLEX CAD и привязать к структуре изделия, но поскольку прикладная часть задачи не очевидна, то сложно определить пути ее решения. Возможно, применение макроса в данном случае излишне. Необходимость в создании 3D-пути нужно для того, чтобы посчитать длину отрезков и вывести в отчет?
T-FLEX CAD 17.1.6.0
 
Цитата
vite написал:
Необходимость в создании 3D-пути нужно для того, чтобы посчитать длину отрезков и вывести в отчет?
Именно так. Я решения без создания 3д пути не смог найти. Или не там искал.
 
Артем, вы можете получить длину сегментов через привязку к ребрам. Затем, привязать переменные к дочерним элементам в структуре изделия (см. вложение). Привязка геометрического объекта к переменной осуществляется через операцию "Измерение".
tf_edges_len.PNG (210.61 КБ)
T-FLEX CAD 17.1.6.0
 
Цитата
vite написал:
вы можете получить длину сегментов через привязку к ребрам. Затем, привязать переменные к дочерним элементам в структуре изделия (см. вложение). Привязка геометрического объекта к переменной осуществляется через операцию "Измерение".

Уже пробовал таким образом. Но печаль такого способа заключается в том что при изменении количества сегментов грани весь расчет рушится. У меня адаптивные фрагменты располагаются по рассеченной области, части этой области могут быть как треугольными, так и н-угольными, как с прямыми участками, так и с криволинейными. Существует ли способ подсчета отрезков без создания пути? Или, допустим, после сбора данных, удалить ненужные уже объекты из модели (3д путь и ребра). Главное результат в структуре изделия сохранить. :)
Изменено: Артем - 05.02.2021 18:55:54
 
Цитата
Артем написал:
Существует ли способ подсчета отрезков без создания пути?
если нужно получить длину с привязкой в структуре изделия, то иного пути нет: либо через измерение, либо через объект построения, типа 3D-путь. Я полагаю, когда создается привязка к ребру через операцию "Измерение", то в дерево модели добавляется новая сущность, которая просто содержит ссылку на ребро. Так что особой разницы нет, какой объект выступает в роли привязки.
T-FLEX CAD 17.1.6.0
 
Цитата
vite написал:
Так что особой разницы нет, какой объект выступает в роли привязки.
Каким образом это можно реализовать? Раз ничего не создается, то нечему и конфликтовать в сборке. А то вот какая неприятность у меня получается. Файлы в закрепе. Деталь 1 это адаптируемый фрагмент, деталь 2 - сборка с ними.
 
Артем, по видимому решить эту задачу на уровне адаптивного фрагмента будет не просто (если вообще такое возможно). В качестве временного решения, можно использовать макрос для создания/обновления существующих записей в структуре изделия. Но чтобы макрос корректно работал, тела должны иметь однородную структуру зависимостей. Я немного поэкспериментировал и вот что у меня получилось.
Код
using System.Linq;
using System.Windows.Forms;
using TFlex.Model;
using TFlex.Model.Data.ProductStructure;
using TFlex.Model.Model3D;
using TFlex.Model.Model3D.Geometry;

namespace Test
{
    public class ProductStructureHelper
    {
        public static void Run()
        {
            var document = TFlex.Application.ActiveDocument;
            if (document == null)
                return;

            var objects = document.Selection.GetAllObjects();
            if (objects.Length == 0)
            {
                MessageBox.Show("Перед запуском макроса, необходимо выбрать объект!", "T-FLEX CAD");
                return;
            }

            foreach (var obj in objects)
            {
                if (obj.GroupType != ObjectType.Extrusion)
                    continue;
                
                var extrusion = obj as ThickenExtrusion;
                if (extrusion == null)
                    continue;
                
                UpdateProductStructure(document, extrusion);
            }
        }

        private static void UpdateProductStructure(Document document, ThickenExtrusion extrusion)
        {
            foreach (var ps in document.GetProductStructures())
            {
                var scheme = ps.GetScheme();
                if (scheme.Name != "Спецификация")
                    continue;

                var pHelper = new ProcHelper(ps, scheme);
                bool updated = false;

                document.BeginChanges("");

                foreach (var row in ps.GetAllRowElements())
                {
                    if (pHelper.GetName(row).Contains("Сегмент") &&
                        row.ParentRowElement.LinkedObjects.Contains(extrusion))
                    {
                        TaskProcessing(extrusion, pHelper, row, 0);
                        updated = true;
                    }
                }

                if (updated)
                {
                    ps.UpdateStructure();
                    document.EndChanges();
                    return;
                }

                var parentRow = ps.AddElement();
                pHelper.SetName(parentRow, extrusion.Name);
                parentRow.LinkedObjects.Add(extrusion);

                TaskProcessing(extrusion, pHelper, parentRow, 1);
                ps.UpdateStructure();

                document.EndChanges();
            }
        }

        private static void TaskProcessing(ThickenExtrusion extrusion, ProcHelper pHelper, RowElement row, int flag)
        {
            for (int i = 0; i < extrusion.Profile.Length; i++)
            {
                var topolRef = (extrusion.Profile[i] as ModelContour).Reference as TopolReference;
                if (topolRef == null)
                    continue;

                var face = topolRef.Topol as ModelFace;
                if (face == null)
                    continue;

                RowElement _row;

                foreach (ModelEdge edge in face.Edges)
                {
                    var id = edge.Identify;
                    if (flag > 0)
                    {
                        _row = pHelper.ProductStructure.AddElement();
                        _row.ParentRowElement = row;
                    }
                    else
                    {
                        _row = row;
                        if (!pHelper.GetName(_row).Contains(id))
                            continue;
                    }

                    var length = edge.Curve.Length(edge.Interval) * 1000;
                    var value = string.Format("Сегмент [id: {0}, len: {1}]",
                        id, length);

                    pHelper.SetName(_row, value);
                }
            }
        }
    }

    public class ProcHelper
    {
        readonly Scheme scheme;

        public ProcHelper(ProductStructure ps, Scheme scheme)
        {
            this.scheme = scheme;
            ProductStructure = ps;
        }

        public ProductStructure ProductStructure { get; }

        public string GetName(RowElement row)
        {
            foreach (var p in scheme.Parameters)
            {
                if (p.SynonymName == "Description")
                {
                    return row[p].Text;
                }
            }
            
            return null;
        }

        public void SetName(RowElement row, string value)
        {
            foreach (var p in scheme.Parameters)
            {
                if (p.SynonymName == "Description")
                {
                    row[p].Text = value;
                    break;
                }
            }
        }
    }
}

Целевые объекты обработки -- это тела, созданные при помощи операции "Выталкивание", с привязкой к граням на базовой форме. По сути, макрос создает записи в структуре изделия с привязкой к операции "Выталкивание" для определения родительского элемента. Дочерние элементы не имеют привязку к ребрам, но они идентифицируются по свойству Identify при повторной обработке записей.
T-FLEX CAD 17.1.6.0
 
Цитата
Артем написал:
это можно реализовать
Дык вы уже это сделали, у вас есть переменная периметр get("Базовая_грань","perimeter") она вам и считает:

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

Цитата
FRei написал:
Дык вы уже это сделали, у вас есть переменная периметр get("Базовая_грань","perimeter") она вам и считает:
Периметр в макросе я считаю только для временного информирования. Что бы проверить его работу. Как и количество отрезков пути. Суть моей задачи в получении длин каждого отрезка грани или 3д профиля по которым вставляется в сборку адаптивный фрагмент для последующих вычислений для каждого фрагмента и занесением результатов в структуру каждого изделия.
 
Цитата
Артем написал:
vite, премного благодарен. В понедельник предметно потестирую.

Цитата
FRei написал:
Дык вы уже это сделали, у вас есть переменная периметр get("Базовая_грань","perimeter") она вам и считает:
Суть моей задачи в получении длин каждого отрезка грани
Тогда предлагаю попробовать вызов макросов событиями:
1. В детали. Хранить длины отрезков, которые вы получаете в БД или хранить в виде переменных l1,l2,l3,...,etc. Записывать в переменные или в БД при помощи макроса. Вызов макроса повесить на события Insert as fragment, Document Full Regenerated;
2. В сборке. Собирать макросом информацию о длинах (чтением БД или наличием переменных) и заносить её в СИ.
Так макросы будут вызываться для каждого отдельного фрагмента только тогда когда это надо.

Делать это одним макросом по всей большой сборке может выйти накладно по производительности.
Изменено: FRei - 07.02.2021 17:37:48
 
Всем доброго времени суток.
Благодаря службе поддержки удалось докопаться до истины, которая лежала на поверхности. Все тривиально: из сборки перебираем фрагменты, проводим необходимые манипуляции с каждым фрагментом, фиксируем их в переменных фрагмента и получаем результат в структуре фрагмента и суммарный в структуре сборки.
Всех благодарю за помощь, код под спойлером.
Пример кода
 
Цитата
vite написал:
эта проблема связана с редактором макросов. Я все тесты создаю в Visual Studio, а в макросе делаю только вызов метода Run().
Не сложно просветить начинающего как это сделать? в VS кодить на порядок удобнее.
 
Цитата
Артем написал:
Не сложно просветить начинающего как это сделать?

1. Нужно создать проект, типа Class Library в Visual Studio.
2. Настроить проект (см. вложение).
3. Добавить ссылку на API в проект.
4. Добавить ссылку вашей библиотеки (DLL) в редакторе макросов.
5. Сделать вызов функции в макросе, например:
Код
using TFlex.Model;
using TFlex.Model.Model2D;
using TFlex.Model.Model3D;

namespace Test
{
   public class TestMacro
   {
      public static void Run()
      {
         ProductStructureHelper.Run();
      }
   }
}

6. Сохранить документ.
7. Запустить отладку в Visual Studio (T-FLEX CAD должен запуститься под отладчиком).
8. Открыть целевой документ обработки.
9. Запустить макрос.
T-FLEX CAD 17.1.6.0
 
vite, благодарю.
Буду разбираться.
 
Артем, вариант обработки посредством метода OpenPart слишком затратный. Если взглянуть на структуру сборки (см. вложение), то видно, что фрагмент "Деталь_1" включает ссылку на топологический элемент "Грань_1 : Сглаживание_1". Вопрос в том, как добраться до него через объект фрагмента.
T-FLEX CAD 17.1.6.0
Страницы: 1 2 След.