.. role:: blue :class: blue Топология полигонального объекта MbPolymeshTopo =============================================== .. _The_Topology_of_the_MbPolymeshTopo_Polygon_Object: .. версия ядра: 118027 Полигональный объект :ref:`MbPolymesh ` является наследником :ref:`MbItem ` и содержит внутри топологию :blue:`MbPolymeshTopo` (по аналогии с :ref:`MbSolid `, который содержит внутри :ref:`MbFaceShell `). Топология включает в себя все методы для работы как с сеткой, так и с сегментацией. Далее будут рассмотрены более подробные описания методов данного класса. Методы общего назначения ------------------------ Метод .. code-block:: cpp static MbPolymeshTopo * Create(); создаёт пустой экземпляр класса. Метод .. code-block:: cpp static MbPolymeshTopo * Create( const MbMesh & mesh, double toleranceSew ); создаёт экземпляр класса по экземпляру :blue:`MbMesh`. Точность сшивки *toleranceSew* используется для объединения почти совпадающих вершин в одну. Метод .. code-block:: cpp bool GetMesh( MbMesh & mesh ) const; создаёт экземпляр MbMesh с потерей топологической информации, где каждому подрегиону соответствует отдельный объект :blue:`MbGrid`. При этом внутри этого экземпляра создаётся (в виде :blue:`MapPolymeshToMbMesh`) отображение между индексами :blue:`MbGrid` и индексами подрегионов, так как в общем случае они будут иметь различную нумерацию. Метод .. code-block:: cpp MbPolymeshTopo * Clone() const; создаёт копию топологии. Метод .. code-block:: cpp void CalculateGabarit( const MbMatrix3D & matrInto, MbCube & bb ) const; рассчитывает габарит объекта. Метод .. code-block:: cpp void Invert(); инвертирует всю топологию, включая разворот циклов вокруг фасетов. Методы трансформации .. code-block:: cpp void Transform( const MbMatrix3D & matr ); void Move ( const MbVector3D & to ); void Rotate ( const MbAxis3D & axis, double angle ); трансформируют все составляющие полигонального объекта, для которых эта операция имеет смысл (3D точки, нормали, направления кривизны и т.д.). Метод .. code-block:: cpp void DeleteInactive(); удаляет все неактивные элементы, уменьшая тем самым размер полигонального объекта (рёбра, вершины, фасеты сетки, рёбра сегментации, вершины сегментации, регионы, подрегионы и циклы сегментации). Метод .. code-block:: cpp double FindNearest( const MbCartPoint3D & pnt, MbCartPoint3D & pntProj, size_t & iFacet ) const; находит ближайшую к указанной точку и индекс фасета, на который она попала. Возвращает расстояние от указанной точки до ближайшей на полигональном объекте. Метод .. code-block:: cpp bool FindLineIntersection( const MbAxis3D & ray, MbCartPoint3D & pntCross, double & tRes, size_t & iFacet ) const; находит ближайшее пересечение с прямой. Выходными параметрами являются точка пересечения, параметр луча и индекс фасета, с которым это пересечение произошло. Метод .. code-block:: cpp const MbFaceShell * GetSubstrateShell() const; обеспечивает доступ к оболочке-подложке (если она существует), из которой полигональный объект был создан. Метод .. code-block:: cpp void DeleteSubstrateShell(); удаляет оболочку-подложку, из которой полигональный объект был создан, а также все сохранённые данные, обеспечивающие отображение от регионов и рёбер сегментации к граням и рёбрам оболочки. Методы для работы с сеткой -------------------------- Метод .. code-block:: cpp const MbHalfedge & GetMeshTopo() const; возвращает топологию сетки в виде объекта :blue:`MbHalfedge`. Это нужно, например, для конструирования сеточных итераторов. Метод .. code-block:: cpp void Reserve( size_t nVx, size_t nEd, size_t nF ); резервирует память под вершины, рёбра и фасеты для сетки и всех атрибутов, которые она содержит. Метод .. code-block:: cpp size_t CloneVertex( size_t iVx ); клонирует вершину сетки и возвращает индекс склонированной вершины. Методы добавления элементов .. code-block:: cpp size_t AddVertex(); size_t AddEdge(); size_t AddFacet(); добавляют активный элемент сетки и возвращают его индекс. Если в сетке есть неактивные элементы, один из них переводится в активное состояние и возвращается его индекс. Методы деактивации элементов .. code-block:: cpp void MakeVertexInactive( size_t iVx ); void MakeEdgeInactive ( size_t iEd ); void MakeFacetInactive ( size_t iF ); переводят элемент сетки в неактивное состояние. Использование должно быть крайне осторожным, так как без дополнительных действий эти методы приведут к невалидности топологии сетки. Метод .. code-block:: cpp void SewEdges( size_t iEd0, size_t iEd1 ); делает два указанных рёбра сетки близнецами. Метод .. code-block:: cpp size_t AddFacet( const c3d::IndicesVector & vertices ); конструирует структуру фасета по указанным вершинам и возвращает его индекс. Вершины на момент вызова должны уже существовать. Метод создаёт фасет, все необходимые рёбра и устанавливает между ними (кроме близнецов) все нужные ссылки. Метод .. code-block:: cpp void SewByVertices(); устанавливает ссылки на близнецов для всех рёбер сетки, используя вершины, из которых исходят рёбра. Используется для окончательного формирования топологии при ручном конструировании, после того как все нужные фасеты были добавлены методом :blue:`AddFacet`\(). Метод .. code-block:: cpp void DeleteFacets( const c3d::IndicesVector & facets ); удаляет указанные фасеты и обеспечивает валидность топологии после этой операции. Удаление неактивных элементов не производится. Пример действий, необходимых для поддержания валидности топологии, показан на рис. 1: в исходном состоянии вершина A одна и та же для всех рёбер веера. После удаления выделенных фасетов веер оказывается разрывным, что не допускается в структуре Halfedge. Поэтому вершина будет склонирована, и части оставшегося веера будет соответствовать вершина A, а другой части её клон B. В этом месте топологически будет разрыв сетки, хотя геометрически эти две вершины совпадают. .. figure:: ../../pictures/P.2.4.2.1.png :width: 21cm :align: center Рис. 1 Метод .. code-block:: cpp bool FlipEdge( size_t iEd ); делает переброску ребра в триангуляции. Нельзя перебрасывать открытые рёбра и рёбра, принадлежащие рёбрам сегментации. Пример работы метода показан на рис. 2: .. figure:: ../../pictures/P.2.4.2.2.png :width: 18cm :align: center Рис. 2 Метод .. code-block:: cpp size_t SplitEdge( size_t iEd, double prm ); разрезает ребро в указанном параметре, значение которого должно быть в интервале от 0 до 1. Возвращает индекс созданной в этом месте двухвалентной вершины. Количество рёбер для смежных фасетов увеличится на единицу. На рис. 3 показан результат после триангуляции двух четырёхугольных смежных фасетов: .. figure:: ../../pictures/P.2.4.2.3.png :width: 18cm :align: center Рис. 3 Метод .. code-block:: cpp void SplitFacet( size_t eVx0, size_t eVx1, c3d::IndicesPair & eNew ); разрезает фасет на два путём вставки пары рёбер между вершинами *v0* и *v1*, из которых исходят указанные рёбра *eVx0*, *eVx1*, и возвращает индексы этих вставленных рёбер. Входные рёбра должны принадлежать одному фасету, который и будет разрезаться. Пример работы показан на рис. 4: .. figure:: ../../pictures/P.2.4.2.4.png :width: 18cm :align: center Рис. 4 Метод .. code-block:: cpp bool JoinEdgeFacets( size_t iEd ); объединяет два фасета, смежных ребру, в один. Это операция, обратная методу :blue:`SplitFacet`\(). Нельзя объединить фасеты, если в результате получится фасет, касающийся сам себя ребром или вершиной. Метод .. code-block:: cpp bool RemoveVertexValence2( size_t iVx ); удаляет двухвалентную вершину сетки. Операция, обратная методу :blue:`SplitEdge`\(). Метод .. code-block:: cpp size_t InsertVertexTriangle( size_t iTr, double u, double v ); вставляет новую вершину в треугольник и разрезает его на три. Возвращает индекс вставленной вершины. Параметры *u* и *v* -- барицентрические координаты, которые определяют новую вершину внутри треугольника. Значения атрибутов для новой вершины (3D точка, 2D параметр, нормаль, кривизна и т.д.) рассчитываются как линейная комбинация из величин в вершинах треугольника согласно барицентрическим координатам. Метод .. code-block:: cpp size_t InsertVertexFacet( const c3d::IndicesVector & edgesSplit, const std::array & edgesInterpolate, double u, double v ); вставляет новую вершину в фасет и разрезает его на несколько новых фасетов путём соединения рёбрами вставленной вершины с вершинами, из которых исходят рёбра из массива *edgesSplit*. Рёбра из этого массива должны принадлежать одному фасету. Массив *edgesInterpolate* определяет «виртуальный» треугольник из вершин фасета, относительно которого задаются барицентрические координаты *u* и *v*. Пример использования показан на рисунке: на рисунке a) чёрным показан фасет, который нужно разбить синей вершиной и фиолетовыми рёбрами; на рисунке b) зелёным цветом показаны рёбра фасета, индексы которых должны быть указаны в массиве *edgesSplit* (они должны быть расположены в порядке следования внутри фасета); на рисунке c) зелёным цветом показан «виртуальный» треугольник, относительно которого задаются барицентрические координаты, а красным – индексы рёбер, которые нужно поместить в массив *edgesInterpolate*. Расчёт значений атрибутов для новой вершины делается аналогично методу :blue:`InsertVertexTriangle`\(). .. figure:: ../../pictures/P.2.4.2.5.png :width: 21cm :align: center Рис. 5 Методы для работы с сегментацией -------------------------------- Метод .. code-block:: cpp bool IsSegmented() const; проверяет, инициализирована ли сегментация. Рекомендуется всегда инициализировать сегментацию. Метод .. code-block:: cpp void Initialize( const MbHalfedgeBoundaryCriterionBase & crit ); инициализирует сегментацию согласно указанному критерию границы. Критерий должен быть реализован пользователем как наследник базового класса :blue:`MbHalfedgeBoundaryCriterionBase`, в котором должна быть заложена логика того, считать ли ребро сетки разделительным или нет. Например, можно предварительно посчитать двугранные углы для рёбер сетки, а в критерии проверять, превышает ли угол заданный порог или нет. Тогда получится сегментация сетки по острым сломам. Метод .. code-block:: cpp void Initialize(); инициализирует сегментацию из одного региона. Сетка разбивается на связные части, каждой из которых назначается подрегион. Сегментационные рёбра образуются из открытых рёбер сетки, если таковые имеются. Рекомендуется всегда инициализировать так сегментацию при ручном создании полигонального объекта. Метод .. code-block:: cpp const MbHalfedge & GetSegmTopo() const; открывает доступ к константной топологии сегментации в виде :blue:`Halfedge`. Нужен для конструирования некоторых сегментационных итераторов. Метод .. code-block:: cpp size_t LoopsCount() const; возвращает количество циклов в сегментации (включая неактивные). Метод .. code-block:: cpp const MbSegmentationLoop & Loop( size_t iLoop ) const; получает цикл сегментации по его индексу. Метод .. code-block:: cpp size_t RegionCount() const; возвращает количество регионов в сегментации (включая неактивные). Метод .. code-block:: cpp bool IsRegionActive( size_t iRegion ) const; проверяет, является ли регион активным. То же самое можно сделать с помощью метода :blue:`IsFacetActive`\() с тем же индексом для топологии сегментации, возвращаемой методом :blue:`GetSegmTopo`\(). Метод .. code-block:: cpp size_t SubRegionsCount() const; возвращает количество подрегионов в сегментации (включая неактивные). Метод .. code-block:: cpp size_t SubRegionsCount( size_t iRegion ) const; возвращает количество подрегионов, входящих в указанный регион. Метод .. code-block:: cpp const MbSegmentationSubRegion & SubRegion( size_t iSub ) const; возвращает подрегион сегментации по его индексу. Метод .. code-block:: cpp size_t EdgeSegmCount() const; возвращает количество рёбер в сегментации (включая неактивные). Метод .. code-block:: cpp const MbHalfedgeEdge & EdgeSegm( size_t iEdSegm ) const; возвращает ребро сегментации по его индексу. Метод .. code-block:: cpp bool IsInnerEdge( size_t iEdSegm ) const; проверяет, является ли ребро сегментации внутренним. Метод .. code-block:: cpp size_t GetSegmEdgeId( size_t iEdTopo ) const; возвращает индекс сегментационного ребра, которому принадлежит указанное сеточное ребро. Метод .. code-block:: cpp void GetFacetRegionId( size_t iFacet, size_t & iRegion, size_t & iSubRegion ) const; возвращает индексы региона и подрегиона, которым принадлежит указанный фасет сетки. Метод .. code-block:: cpp size_t VertexSegmCount() const; получает количество вершин в сегментации (включая неактивные). Метод .. code-block:: cpp const MbHalfedgeVertex & VertexSegm( size_t iVxSegm ) const; возвращает вершину сегментации по её индексу. Метод .. code-block:: cpp void GetRegion( size_t r, c3d::IndicesVector & facets ) const; возвращает индексы всех фасетов сетки, входящих в указанный регион. Метод .. code-block:: cpp void GetSubRegion( size_t iSub, c3d::IndicesVector & facets, bool bAdd = false ) const; возвращает индексы всех фасетов сетки, входящих в указанный подрегион. Метод .. code-block:: cpp void DeleteRegion( size_t iRegion ); удаляет указанный регион. При этом поддерживается валидность топологии и сетки, и сегментации, аналогично удалению фасетов. Метод .. code-block:: cpp void SplitByEdgesTopo( const c3d::IndicesVector & splitSet, bool bKeepRegions ); разбивает существующую сегментацию набором рёбер сетки. Это может привести к появлению новых связанных групп фасетов. Для каждого из них создаётся новый подрегион. По флагу :blue:`bKeepRegions` эти подрегионы либо остаются в составе старого региона, либо из каждого из них будет создан новый регион. Также эта операция может привести к появлению внутренних рёбер сегментации. Метод .. code-block:: cpp void MergeRegions( const c3d::IndicesVector & regions, bool bRemoveValence2 ); объединяет указанные регионы в один. Его индекс равен первому индексу из массива *regions*. При этом могут образоваться последовательности рёбер сегментации, разделённые двухвалентными сегментационными вершинами. По флагу :blue:`bRemoveValence2` эти последовательности объединяются в рёбра сегментации. Метод .. code-block:: cpp void SplitByFacetsTopo( const c3d::IndicesVector & splitSet, bool bMakeOneRegion, bool bKeepRegions ); разбивает существующую сегментацию набором фасетов сетки. Этому набору соответствует один или несколько связных групп фасетов, относящихся к старым регионам и каждой из которых назначается новый подрегион. Комбинация этих групп в новые регионы и подрегионы зависит от двух управляющих флагов :blue:`bMakeOneRegion` и :blue:`bKeepRegions`. Пример показан на рис. 6, пусть сегментация состоит из четырёх простых регионов, которые нужно разбить выделенными ярко зелёным фасетами: .. figure:: ../../pictures/P.2.4.3.1.png :width: 18cm :align: center Рис. 6 1. :blue:`bMakeOneRegion` = true, :blue:`bKeepRegions` = true. Выделенные фасеты образовали один новый регион (жёлтый). Старые регионы остались, но разделились каждый на два подрегиона. Теперь в сегментации 5 регионов (рис. 7). .. figure:: ../../pictures/P.2.4.3.2.png :width: 12cm :align: center Рис. 7 2. :blue:`bMakeOneRegion` = true, :blue:`bKeepRegions` = false. Выделенные фасеты образовали один новый регион (жёлтый). Каждый из старых регионов распался на две несвязные части, каждая из которых образовала новый отдельный регион. Всего теперь в сегментации 9 регионов (рис. 8). .. figure:: ../../pictures/P.2.4.3.3.png :width: 12cm :align: center Рис. 8 3. :blue:`bMakeOneRegion` = false, :blue:`bKeepRegions` = true. Выделенные фасеты разбили каждый из старых регионов на 3 части. Регионов в сегментации по-прежнему 4, но каждый из них теперь состоит из трёх подрегионов (рис. 9). .. figure:: ../../pictures/P.2.4.3.4.png :width: 12cm :align: center Рис. 9 4. :blue:`bMakeOneRegion` = false, :blue:`bKeepRegions` = false. Выделенные фасеты разбили каждый из старых регионов на 3 части. Каждой такой части назначен новый регион. Всего теперь в сегментации 12 регионов, состоящих из одного подрегиона (рис. 10). .. figure:: ../../pictures/P.2.4.3.5.png :width: 12cm :align: center Рис. 10 Метод .. code-block:: cpp void SplitRegionBySubregions( size_t iReg ); выделяет подрегионы региона как отдельные регионы. Метод .. code-block:: cpp c3d::IndicesPair SplitSegmentationEdge( size_t iEdSegm, size_t iEdTopo, size_t iVxSegmSplit = SYS_MAX_T ); разрезает ребро сегментации с индексом *iEdSegm* (и его близнеца) в вершине сетки, из которой исходит сеточное ребро *iEdTopo*. Ребро *iEdTopo* должно принадлежать сегментационному ребру и не должно совпадать с самым первым сеточным ребром для сегментационного ребра. В этом месте возникнет двухвалентная вершина сегментации, существующая с индексом *iVxSegmSplit*, если он задан, либо будет добавлена новая. Возвращает индексы новых рёбер сегментации, на которые распалось старое ребро сегментации и его близнец (если он существует). Топологию сетки метод не изменяет. Новые рёбра сегментации наследуют атрибуты от старых, из которых они были получены. Метод .. code-block:: cpp bool ExtractSubRegionAsRegion( size_t iSub ); выделяет указанный подрегион в отдельный регион. Если старый регион состоял только из указанного подрегиона, никаких действий выполнено не будет. Метод .. code-block:: cpp void RemoveSegmVertexValence2( size_t iVx ); удаляет вершину сегментации с валентностью 2. Метод, обратный к :blue:`SplitSegmentationEdge`\(). Метод .. code-block:: cpp size_t GetTopoVertex( size_t iVxSegm ) const; возвращает индекс вершины сетки, в которой находится указанная вершина сегментации. Метод .. code-block:: cpp size_t GetSegmEdgeRegionId( size_t iEdSegm ) const; возвращает индекс региона, которому принадлежит ребро сегментации. Метод .. code-block:: cpp size_t GetSegmEdgeSubRegionId( size_t iEdSegm ) const; возвращает индекс подрегиона, которому принадлежит ребро сегментации. Метод .. code-block:: cpp size_t GetLoopRegionId( size_t iLoop ) const; возвращает индекс региона, которому принадлежит цикл. Метод .. code-block:: cpp size_t GetLoopSubRegionId( size_t iLoop ) const; возвращает индекс подрегиона, которому принадлежит цикл. Метод .. code-block:: cpp size_t GetNeighborRegionId( size_t iEdSegm ) const; возвращает индекс региона с другой стороны ребра сегментации. Метод .. code-block:: cpp size_t GetNeighborSubRegionId( size_t iEdSegm ) const; возвращает индекс подрегиона с другой стороны ребра сегментации. Методы для работы с атрибутами сетки и сегментации -------------------------------------------------- Метод .. code-block:: cpp size_t MeshHalfedgeAttributeCount() const; возвращает количество сеточных атрибутов. Метод .. code-block:: cpp size_t SegmHalfedgeAttributeCount() const; возвращает количество сегментационных атрибутов. Метод .. code-block:: cpp template T * AddMeshHalfedgeAttribute(); создаёт сеточный атрибут указанного типа и возвращает указатель на него. Метод .. code-block:: cpp template T * AddSegmHalfedgeAttribute(); добавляет сегментационный атрибут указанного типа и возвращает указатель на него. Метод .. code-block:: cpp template T * GetMeshHalfedgeAttribute(); и константный вариант .. code-block:: cpp template const T * GetMeshHalfedgeAttribute() const; находят в полигональном объекте сеточный атрибут указанного типа (первый подходящий в массиве атрибутов) и возвращают указатель на него. Метод .. code-block:: cpp template T * GetSegmHalfedgeAttribute(); и константный вариант .. code-block:: cpp template const T * GetSegmHalfedgeAttribute() const; находят в полигональном объекте сегментационный атрибут указанного типа (первый подходящий в массиве атрибутов) и возвращают указатель на него. Метод .. code-block:: cpp template void DeleteMeshHalfedgeAttribute(); удаляет сеточный атрибут указанного типа (первый подходящий в массиве атрибутов). Метод .. code-block:: cpp template void DeleteSegmHalfedgeAttribute(); удаляет сегментационный атрибут указанного типа (первый подходящий в массиве атрибутов). Методы .. code-block:: cpp MbHalfedgeAttrBase * GetMeshHalfedgeAttributeByIndex( size_t ind ); const MbHalfedgeAttrBase * GetMeshHalfedgeAttributeByIndex( size_t ind ) const; возвращают указатель на сеточный атрибут с заданным индексом в массиве атрибутов. Методы .. code-block:: cpp MbHalfedgeAttrBase * GetSegmHalfedgeAttributeByIndex( size_t ind ); const MbHalfedgeAttrBase * GetSegmHalfedgeAttributeByIndex( size_t ind ) const; возвращают указатель на сегментационный атрибут с заданным индексом в массиве атрибутов. Метод .. code-block:: cpp void DeleteMeshHalfedgeAttribute( MbHalfedgeAttrBase * pAttr ); удаляет указанный сеточный атрибут. Метод .. code-block:: cpp void DeleteSegmHalfedgeAttribute( MbHalfedgeAttrBase * pAttr ); удаляет указанный сегментационный атрибут. Метод .. code-block:: cpp MbAttributeContainer * GetSegmRegionModelAttributes( size_t iRegion, bool bCreate ); возвращает контейнер атрибутов объекта геометрического ядра для региона. Если он отсутствует, то по флагу :blue:`bCreate` будет создан, иначе возвращается нулевой указатель. Метод .. code-block:: cpp const MbAttributeContainer * GetSegmRegionModelAttributes( size_t iRegion ) const; возвращает контейнер атрибутов объекта геометрического ядра для региона. Метод .. code-block:: cpp MbAttributeContainer * GetSegmEdgeModelAttributes( size_t iEdSegm, bool bCreate ); возвращает контейнер атрибутов объекта геометрического ядра для ребра сегментации. Если он отсутствует, то по флагу *bCreate* будет создан, иначе возвращается нулевой указатель. Метод .. code-block:: cpp const MbAttributeContainer * GetSegmEdgeModelAttributes( size_t iEdSegm ) const; возвращает контейнер атрибутов объекта геометрического ядра для ребра сегментации. Метод .. code-block:: cpp MbAttributeContainer * GetSegmVertexModelAttributes( size_t iVxSegm, bool bCreate ); возвращает контейнер атрибутов объекта геометрического ядра для вершины сегментации. Если он отсутствует, то по флагу :blue:`bCreate` будет создан, иначе возвращается нулевой указатель. Метод .. code-block:: cpp const MbAttributeContainer * GetSegmVertexModelAttributes( size_t iVxSegm ) const; возвращает контейнер атрибутов объекта геометрического ядра для вершины сегментации.