Инструменты пользователя

Инструменты сайта


developers:tutorial:sfcselection

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
developers:tutorial:sfcselection [2022/03/02 20:42]
proxor [Выделение элементов поверхности]
developers:tutorial:sfcselection [2022/04/09 18:55] (текущий)
proxor [Выделение горизонталей]
Строка 1: Строка 1:
 ====== Выделение элементов поверхности ====== ====== Выделение элементов поверхности ======
  
-Нередко,​ при работе с поверхностью,​ пользователю требуется изменять или получать информацию из её элементов. В этой главе мы рассмотрим простые примеры по работе с элементами поверхности.+Нередко,​ при работе с [[road:​work_with_cmm:​create_and_edit_surface_new:​basic_terms_and_definition_new|поверхностью]], пользователю требуется изменять или получать информацию из её элементов. В этой главе мы рассмотрим простые примеры по работе с элементами поверхности.
  
-В качестве основного инструмента получения элементов поверхности рекомендуется пользоваться методами ​класса ​''​SurfaceLayer''​некоторые из них мы рассмотрим в следующих примерах. Сперва выберем необходимые нам объекты и начнём мы с выбора точек ​поверхности. ​+Программноповерхность представляет из себя экземпляр класса ​[[developers:​references:​topomatic.sfc.surface|Surface]]. Этот класс ​содержит в себе все элементы поверхности.
  
 +Основные элементы класса [[developers:​references:​topomatic.sfc.surface|Surface]] это:
 +  * [[developers:​references:​topomatic.sfc.surface.points|Surface.Points]] - массив [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_dots_new|точек поверхности]] типа [[developers:​references:​topomatic.sfc.surfacepointarray|SurfacePointArray]]
 +  * [[developers:​references:​topomatic.sfc.surface.structurelines|Surface.StructureLines]] - коллекция [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_structural_lines_new|структурных линий]] содержащихся в поверхности типа [[developers:​references:​topomatic.sfc.structurelines|StructureLines]]
 +  * [[developers:​references:​topomatic.sfc.surface.triangles|Surface.Triangles]] - массив треугольников отписывающих кривизну рельефа типа [[developers:​references:​topomatic.sfc.surfacetrianglearray|SurfaceTriangleArray]]
 +  * [[developers:​references:​topomatic.sfc.surface.patchs|Surface.Patchs]] - массив [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_of_parcels_new|участков]] типа [[developers:​references:​topomatic.sfc.surfacepatcharray|SurfacePatchArray]]
 +
 +Базовыми элементами поверхности являются точки поверхности и структурные линии. Опираясь на них, в модели поверхности формируется триангуляция состоящая из треугольников,​ которые в свою очередь способны объединяться в участки,​ а так же на основе которых генерируются горизонтали. Более подробно о работе с элементами поверхности в программном комплексе [[http://​topomatic.ru|Топоматик Робур]] можно ознакомиться [[road:​work_with_cmm:​create_and_edit_surface_new:​start|здесь]].
 +
 +Прежде чем приступить работе с элементами поверхности,​ создайте и настройте новый [[developers:​tutorial:​module|модуль]] для подключения к программному комплексу [[http://​www.topomatic.ru|Топоматик Робур]]. ​
 +
 +С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки:​
 +  * [[developers:​references:​topomatic.cad.foundation|Topomatic.Cad.Foundation.dll]] - базовые математические типы и операции
 +  * [[developers:​references:​topomatic.cad.view|Topomatic.Cad.View.dll]] - элемент управления для отображения слоёв моделей
 +  * [[developers:​references:​topomatic.dwg|Topomatic.Dwg.dll]] - примитивы и модель чертежа
 +  * [[developers:​references:​topomatic.sfc|Topomatic.Sfc.dll]] - поверхность
 +  * [[developers:​references:​topomatic.sfc.layer|Topomatic.Sfc.Layer.dll]] - слой поверхности
 +
 +В качестве основного инструмента получения элементов поверхности рекомендуется пользоваться методами слоя поверхности ''​SurfaceLayer''​. Для получения текущего ''​SurfaceLayer'',​ необходимо воспользоваться статическим методом ''​SurfaceLayer.GetSurfaceLayer(cadview)''​. В качестве аргумента метод принимает видовой экран [[developers:​references:​topomatic.cad.view.cadview|CadView]],​ который мы получаем пользуясь свойством ''​CadView''​ [[developers:​tutorial:​module|нашего модуля]].
 +
 +==== Множественный выбор ====
 +''​SurfaceLayer''​ предоставляет широкий набор инструментов для выделения элементов поверхности. Ниже описаны методы позволяющие пользователю осуществить выбор:
 +  * SurfaceLayer.SelectPoints() - выделение [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_dots_new|точек поверхности]]
 +  * SurfaceLayer.SelectStructureLines() - выделение [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_structural_lines_new|структурных линий]]
 +  * SurfaceLayer.SelectPatches() - выделение [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_of_parcels_new|участков]]
 +
 +Все перечисленные методы принимают одинаковый набор аргументов и возвращают результат выполнения пользовательского запроса типа [[developers:​references:​topomatic.cad.view.getpointresult|GetPointResult]].
 +
 +В качестве первого аргумента,​ принимается предикат выполняющий роль фильтра выделяемых объектов. Предикат должен возвращать значение типа ''​bool'',​ которое указывает на необходимость выделения объекта описанного в предикате. На входе у предиката принимается индекс выбираемого элемента в множестве соответствующем его типу. Например мы хотим ограничиться выбором только ситуационных точек, тогда код должен выглядеть следующим образом:​
 +
 +<code csharp>
 + var result = surfaceLayer.SelectPoints(i => surfaceLayer.Surface.Points[i].IsSituation,​ "​Выделите ситуационные точки:"​);​
 +</​code>​
 +
 +В качестве второго аргумента принимается текст сообщения выводящийся пользователю на экран во время выполнения команды.
 +
 +Третий представляет из себя массив строк. Аргумент является опциональным и может не использоваться. Он позволяет предоставить пользователю возможность осуществить выбор из предложенных ему вариантов.
 +
 +Возвращаемое значение [[developers:​references:​topomatic.cad.view.getpointresult|GetPointResult]] указывает на то, какое действие было совершено пользователем. Пользователь может выделить элементы поверхности и подтвердить выбор (''​Accept''​),​ отменить действие (''​Cancel''​) или выбрать один из предложенных вариантов контекстного меню (''​UserCmd''​).
 +
 +<​note>​Значение ''​UserCmd''​ возвращается только в том случае,​ если в качестве третьего аргумента был передан массив строк и пользователь выбрал одно из предложенных значений. Чтобы понять какой именно ​ пункт был выбран пользователем,​ следует воспользоваться свойством [[developers:​references:​topomatic.cad.view.cadview.lastusercmd|CadView.LastUserCmd]].</​note>​
 +
 +==== Одиночный выбор ====
 +Так же ''​SurfaceLayer''​ располагает возможностью выделения одного конкретного объекта:​
 +  * SurfaceLayer.PickOnePoint() - выделение одной [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_dots_new|точки поверхности]]. В качестве аргументов принимаются предикат-фильтр,​ аналогично описанному ранее, переменная типа ''​int''​ с модификатором ''​out'',​ в которую будет сохранён индекс выбранной точки, сообщение пользователю и массив строк с вариантами пользовательского выбора. Возвращаемое значение [[developers:​references:​topomatic.cad.view.getpointresult|GetPointResult]],​ описанное выше.
 +  * SurfaceLayer.SelectOneStructureLine() - выделение одной [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_structural_lines_new|структурной линии]]. Аргументы предикат-фильтр и сообщение пользователю. Метод возвращает саму [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_structural_lines_new|структурную линию]].
 +  * SurfaceLayer.SelectOnePatch() - выбор одного [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_of_parcels_new|участка]]. Аргументы предикат-фильтр и сообщение пользователю. Метод возвращает индекс участка из [[road:​work_with_cmm:​create_and_edit_surface_new:​notion_of_parcels_new|массива участков]].
 ===== Выделение точек поверхности ===== ===== Выделение точек поверхности =====
 В этом примере мы выберем точки поверхности на вкладке "​План"​ и рассчитаем их среднюю отметку. В этом примере мы выберем точки поверхности на вкладке "​План"​ и рассчитаем их среднюю отметку.
-Для этого воспользуемся методом ''​SelectPoints()''​ у слоя текущей поверхности (''​SurfaceLayer''​). ​Выбранные точки необходимо будет ​получить ​так же у ''​SurfaceLayer'' ​с помощью метода ''​GetSelectedPoints()''​. Далее пройдёмся по выбранным точкам циклом ''​foreach''​ и применим ​необходимую логику для расчёта средней ​отметки+Для этого воспользуемся методом ''​SelectPoints()''​ у слоя текущей поверхности (''​SurfaceLayer''​). ​Так как метод ''​SelectPoints()''​ предоставляет пользователю возможность выбора элементов контекстного меню, то возвращаемое значение ​будет иметь вид ​''​GetPointResult''​, которое укажет на то, какое именно действие было совершено пользователем
 + 
 +Для того чтобы ​получить множество выбранных точек, будет необходимо ​воспользоваться методом ​''​GetSelectedPoints()''​ у того же ''​SurfaceLayer''​.
  
-Ниже представлен код ​примера, который ​мы оформим ​в качестве метода ''​CalculateAverageElevation()''​ с атрибутом ​''​[cmd("​calculate_average_elevation"​)]''​Данный метод мы поместим в класс ''​Module'' ​для возможности последующего ​вызова этой команды из командной строки.+В теле программного модуля ​объявите ​команду, и декорируйте её атрибутом ​«cmd»Команда "​calculate_average_elevation" ​предложит пользователю выбрать точки поверхности и посчитает их среднюю отметку.
  
 <code csharp> <code csharp>
Строка 46: Строка 94:
 } }
 </​code>​ </​code>​
 +
 +{{ :​developers:​tutorial:​surfaceelementsselect:​tutselpoints.png?​nolink&​600 |}}
 +
 +
 +
  
 ===== Выделение структурных линий ===== ===== Выделение структурных линий =====
-Как и в предыдущем примере,​ для выбора структурной линии нам потребуется слой текущей поверхности (''​SurfaceLayer''​). Чтобы выбрать одну структурную линию, воспользуемся методом ''​SelectOneStructureLine()''​. Здесь возвращаемым значением сразу же будет выступать выбранная структурная линии, поэтому никаких дополнительных действий выполнять не придется.+В данном примере мы рассчитаем максимальный уклон среди всех сегментов структурной линии. 
 +Как и в предыдущем примере,​ для выбора структурной линии нам потребуется слой текущей поверхности (''​SurfaceLayer''​). Чтобы выбрать одну структурную линию, воспользуемся методом ''​SelectOneStructureLine()''​. Здесь возвращаемым значением сразу же будет выбранная [[developers:​references:​topomatic.sfc.structureline|структурная линия]], ​поэтому никаких дополнительных действий ​выполнять не придется. 
 + 
 +<​note>​Важно помнить,​ что [[developers:​references:​topomatic.sfc.structurelinenode|узел структурной линии]] всегда опирается на [[developers:​references:​topomatic.sfc.surfacepoint|точку поверхности]],​ индекс которой хранится в поле [[developers:​references:​topomatic.sfc.structurelinenode.index|StructureLineNode.Index]]. Узел не несёт информации о его плановом положении,​ но при помощи индекса опорной точки, мы можем найти её в [[developers:​references:​topomatic.sfc.surfacepointarray|массиве точек поверхности]] и получить необходимые данные о расположении этого узла в пространстве.</​note>​ 
 + 
 +В теле программного модуля объявите команду,​ и декорируйте её атрибутом «cmd». Команда «define_steepest_grade» предложит пользователю выбрать ​структурную линию и определит максимальный уклон среди всех её сегментов. 
 + 
 +<code csharp>​ 
 +
 +... 
 +    [cmd("​define_steepest_grade"​)] 
 +    private void DefineSteepestGrade() 
 +    { 
 +        //​Находим активный SurfaceLayer 
 +        var cadview = CadView; 
 +        var actSfcLayer = SurfaceLayer.GetSurfaceLayer(cadview);​ 
 +        if (actSfcLayer == null) return; 
 + 
 +        //​Выбираем структурную линию 
 +        var strLine = actSfcLayer.SelectOneStructureLine(null,​ "​Выберите структурную линию:"​);​ 
 +        if (strLine == null) return; 
 + 
 +        //​Обращаемся к узлам структурной ​линии, ​находим соответствующие им точки ​поверхности 
 +        //и высчитываем уклоны сегментов по пути определяя максимальный уклон 
 +        var sfc = actSfcLayer.Surface;​ 
 +        var maxIncline = 0.0; 
 +        for (var i = 0; i < strLine.Count - 1; i++) 
 +        { 
 +            var stPoint = sfc.Points[strLine[i].Index];​ 
 +            var endPoint = sfc.Points[strLine[i + 1].Index];​ 
 +            var delta = Math.Abs(stPoint.Vertex.Elevation - endPoint.Vertex.Elevation);​ 
 + 
 +            var stPos = stPoint.Vertex.Pos;​ 
 +            var endPos = endPoint.Vertex.Pos;​ 
 +            var length = (endPos - stPos).Length;​ 
 +             
 +            if (ValueConverter.CompValues(length,​ 0.0) != 0) 
 +            { 
 +                var incline = delta / length; 
 +                if (incline > maxIncline) maxIncline = incline; 
 +            } 
 +        } 
 + 
 +        MessageDlg.Show($"​Максимальный уклон: {maxIncline}"​);​ 
 +    } 
 +... 
 +
 +</​code>​ 
 + 
 +{{ :​developers:​tutorial:​surfaceelementsselect:​tutselstrline.png?​nolink&​600 |}} 
 +===== Выделение горизонталей ===== 
 +По умолчанию,​ в программном ​комплексе [[http://​topomatic.ru|Топоматик Робур]],​ выделение горизонталей отключено. Чтобы включить выделение горизонталей нужно изменить значение статического свойства ''​SurfaceLayer.SurfaceSelectionSet.IsHorizontalSelectable''​ на ''​true''​. Взаимодействовать с объектами горизонталей напрямую нельзя,​ но горизонтали реализуют интерфейс [[developers:​references:​topomatic.cad.foundation.ilinearobject|ILinearObject]],​ поэтому мы можем получить [[developers:​references:​topomatic.cad.foundation.polyline3d|трёхмерную полилинию]] описывающую положение горизонтали,​ воспользовавшись методом [[developers:​references:​topomatic.cad.foundation.ilinearobject.getpolyline_topomatic.cad.foundation.ipolyline3d|GetPolyline()]]. Для ​получения площади [[developers:​references:​topomatic.cad.foundation.polyline3d|трёхмерной полилинии]] воспользуемся методом расширения [[developers:​references:​topomatic.cad.foundation.polylineextentions.getarea2d_topomatic.cad.foundation.ipolyline3d|PolylineExtentions.GetArea2D(IPolyline3D)]] 
 + 
 +В теле программного модуля объявите команду,​ и декорируйте её атрибутом «cmd». Команда "​get_horizontal_line_area"​ предложит пользователю выбрать замкнутую горизонталь и определит её площадь. 
 + 
 +<code csharp>​ 
 +... 
 +    [cmd("​get_horizontal_line_area"​)] 
 +    private void GetHorizontalLineArea() 
 +    { 
 +        //​Находим активный SurfaceLayer 
 +        var cadview = CadView; 
 +        var actSfcLayer = SurfaceLayer.GetSurfaceLayer(cadview);​ 
 +        if (actSfcLayer == null) return; 
 + 
 +        //​Включаем возможность выбор горизонталей 
 +        var initSelectState = SurfaceLayer.SurfaceSelectionSet.IsHorizontalSelectable;​ 
 +        SurfaceLayer.SurfaceSelectionSet.IsHorizontalSelectable = true; 
 + 
 +        //​Получаем указатель на текущий набор объектов 
 +        var ss = actSfcLayer.SelectionSet;​ 
 + 
 +        //​Получаем указатель на слой горизонталей 
 +        var layer = actSfcLayer.Surface.Style.HorizontalsStyle.GetLayer();​ 
 + 
 +        //Выбираем горизонталь на плане 
 +        var linear_object = ss.PickOneObjectAtScreen(obj => 
 +        { 
 +            if (obj is SurfaceObjectWrapper layered_object) 
 +            { 
 +                return layered_object.LayerID == layer.ObjectID;​ 
 +            } 
 +            return false; 
 +        }, "​Выберите замкнутую горизонталь") as ILinearObject;​ 
 + 
 +        //​Восстанавливаем состояние флага возможности выбора горизонталей 
 +        SurfaceLayer.SurfaceSelectionSet.IsHorizontalSelectable = initSelectState;​ 
 +        if (linear_object == null) return; 
 + 
 +        //​Извлекаем полилинию из горизонтали и получаем её площадь 
 +        var poly = new Polyline3D();​ 
 +        linear_object.GetPolyline(poly);​ 
 + 
 +        //​Проверяем замкнута ли горизонталь 
 +        var startVec = poly[0]; 
 +        var endVec = poly[poly.Count - 1]; 
 +        if (startVec.EqualEps(endVec)) 
 +        { 
 +            var area = poly.GetArea2D();​ 
 +            MessageDlg.Show($"​Площадь горизонтали:​ {area}"​);​ 
 +        } 
 +        else MessageDlg.Show($"​Горизонталь не замкнута."​);​ 
 +    } 
 +... 
 +</​code>​ 
 + 
 +{{ :​developers:​tutorial:​surfaceelementsselect:​tutselhorizontal.png?​nolink&​600 |}} 
 + 
 + 
 + 
 +Теперь необходимо сформировать наш файл .plugin. Заполните его следующим образом. 
 + 
 +<code javascript>​ 
 +
 +  "​assemblies":​ { 
 +    "​TutorialSelectSurfaceElements":​ { 
 +      "​assembly":​ "​TutorialSelectSurfaceElements.dll,​ TutorialSelectSurfaceElements.ModulePluginHost"​ 
 +    } 
 +  }, 
 + 
 +  "​actions":​ { 
 +    "​id_calculate_average_elevation":​ { 
 +      "​cmd":​ "​calculate_average_elevation",​ 
 +      "​title":​ "​Рассчитать среднюю отметку"​ 
 +    }, 
 +    "​id_define_steepest_grade":​ { 
 +      "​cmd":​ "​define_steepest_grade",​ 
 +      "​title":​ "Рассчитать наибольший уклон"​ 
 +    }, 
 +    "​id_get_horizontal_line_area":​ { 
 +      "​cmd":​ "​get_horizontal_line_area",​ 
 +      "​title":​ "​Получить площадь горизонтали"​ 
 +    } 
 +  }, 
 + 
 +  "​menubars":​ { 
 +    "​rbproj":​ { 
 +      "​items":​ [ 
 +        { 
 +          "​id":​ "​tutorial_menu",​ 
 +          "​title":​ "​Tutorial",​ 
 +          "​items":​ [ 
 +            "​id_calculate_average_elevation",​ 
 +            "​id_define_steepest_grade",​ 
 +            "​id_get_horizontal_line_area"​ 
 +          ] 
 +        } 
 +      ] 
 +    } 
 +  } 
 +
 +</​code>​ 
 + 
 +Результатом запуска проекта будет появление в главном меню пункта «Tutorial»,​ с подпунктами,​ которые будут работать в соответствии с описанными выше алгоритмами. 
 + 
 +<​note>​[[developers:​tutorial:​tutorialcode|Исходный код]] примера расположен в проекте **"​TutorialSelectSurfaceElements"​**.</​note>​
developers/tutorial/sfcselection.1646253735.txt.gz · Последние изменения: 2022/03/02 20:42 — proxor