Здесь показаны различия между двумя версиями данной страницы.
Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
developers:tutorial:customentity [2022/12/07 11:44] proxor [Контроллер пользовательского примитива.] |
developers:tutorial:customentity [2022/12/15 13:14] (текущий) proxor [Контроллер пользовательского примитива.] |
||
---|---|---|---|
Строка 1: | Строка 1: | ||
====== Создание пользовательского примитива ====== | ====== Создание пользовательского примитива ====== | ||
- | Программный комплекс Топоматик Робур позволяет разрабатывать пользовательские примитивы. **Примитив** - это элемент чертежа, обладающий графическим отображением в области рисования. Условно, примитивы можно разделить на простые и сложные. К простым относятся точка, отрезок, дуга, окружность, луч, прямая, эллипс или однострочный текст. К сложным все остальные. | + | Программный комплекс Топоматик Робур позволяет разрабатывать пользовательские примитивы. **Примитив** - это элемент модели чертежа. Каждый примитив умеет отобразить себя в чертеже, и при необходимости в окне 3D вида. |
- | + | ||
- | Особенностью разработки примитива в комплексе Топоматик Робур является возможность связать его с 3D-моделью, а также элементом информационной модели (ИМ). 3D-модель служит для отображения объекта на 3D виде. Элемент ИМ обладает семантическими свойствами, отображаемыми при работе со сводной информационной моделью. | + | |
==== Создание пользовательского примитива ==== | ==== Создание пользовательского примитива ==== | ||
Для создания пользовательского примитива необходимы следующие действия | Для создания пользовательского примитива необходимы следующие действия | ||
- | - Создание класса примитива | + | - Создание класса примитива, наследника от **DwgEntity** и связь его с чертежом и контроллером через атрибуты **DesignAliasAttribute** и **EntityControllerAttribute**. |
- | - Создание класса обёртки примитива для работы с инспектором свойств | + | - Создание класса контроллера примитива, наследника от **DwgEntityController**. Он служит для графического отображения на плане и 3D-виде |
- | - Создание класса контроллера примитива для определения его графического отображения | + | |
- Создание команды добавления примитива на план | - Создание команды добавления примитива на план | ||
- | Для связывания примитива с 3D-моделью рассмотрим процесс создания пользовательской библиотеки 3D-объектов. Во время создания библиотеки, мы также создадим пользовательские элементы ИМ и свяжем их с 3D-моделями. Этот процесс не является обязательным. | + | |
- | Подготовка модуля | + | ==== Подготовка модуля ==== |
Создайте и настройте новый модуль для подключения к программному комплексу Топоматик Робур. | Создайте и настройте новый модуль для подключения к программному комплексу Топоматик Робур. | ||
С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки: | С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки: | ||
Строка 19: | Строка 17: | ||
* Topomatic.Cad.View.dll - элемент управления для отображения слоёв моделей | * Topomatic.Cad.View.dll - элемент управления для отображения слоёв моделей | ||
* Topomatic.ComponentModel.dll – атрибуты свойств класса | * Topomatic.ComponentModel.dll – атрибуты свойств класса | ||
- | * Topomatic.Dwg.dll –классы элементов области рисования | + | * Topomatic.Dwg.dll – элементы области рисования |
* Topomatic.Dwg.Layer.dll – слои области рисования | * Topomatic.Dwg.Layer.dll – слои области рисования | ||
- | * Topomatic.Visualization.dll - классы элементов информационной модели | + | * Topomatic.Visualization.dll - элементы информационной модели |
==== Пользовательский примитив ==== | ==== Пользовательский примитив ==== | ||
- | В этом примере мы создадим точечный пользовательский примитив и свяжем его с пользовательской 3D-моделью и элементом ИМ. Класс примитива содержит много кода, поэтому для удобства сделаем его разделяемым применив модификатор **partial**. | + | В этом примере мы создадим точечный пользовательский примитив и свяжем его с и элементом ИМ содержащим 3D-модель. |
- | Создадим класс примитива. Класс должен наследовать абстрактный тип **DwgEntity**. Для связи с элементом ИМ также необходимо реализовать интерфейс **IConstructionModelHolder**. Перекроем необходимые методы и свойства, а также добавим свои для возможности изменять состояние примитива через окно свойств. Класс декорируется атрибутами **DesignAliasAttribute** и **EntityControllerAttribute**. | + | Создадим класс примитива. Класс должен наследовать абстрактный тип **DwgEntity**. Для связи с элементом ИМ также добавим свойство **Element** типа **ImElement**. Перекроем необходимые методы и свойства, а также добавим свои для возможности изменять состояние примитива через окно свойств. Класс декорируется атрибутами **DesignAliasAttribute** и **EntityControllerAttribute**. |
В методе **OnRegen()** необходимо переопределять границы примитива (свойство **Bounds**). | В методе **OnRegen()** необходимо переопределять границы примитива (свойство **Bounds**). | ||
Строка 34: | Строка 32: | ||
- **Position** – координаты примитива | - **Position** – координаты примитива | ||
- **Angle** – угол поворота | - **Angle** – угол поворота | ||
- | - **Scale** – масштаб | ||
- **Element** – элемент ИМ | - **Element** – элемент ИМ | ||
+ | |||
Добавим метод **GetPlan()** возвращающий блок (**DwgBlock**) содержащий примитивы для отображения на плане. В нашем случает блок формируется с помощью метода **GetView()** элемента ИМ (класс **ImViewElement**). | Добавим метод **GetPlan()** возвращающий блок (**DwgBlock**) содержащий примитивы для отображения на плане. В нашем случает блок формируется с помощью метода **GetView()** элемента ИМ (класс **ImViewElement**). | ||
Добавьте в программу новый класс со следующим содержанием: | Добавьте в программу новый класс со следующим содержанием: | ||
Строка 43: | Строка 41: | ||
[EntityController(typeof(CustomDwgEntityController))] | [EntityController(typeof(CustomDwgEntityController))] | ||
[DesignAlias("CUSTOMDWGENTITY")] | [DesignAlias("CUSTOMDWGENTITY")] | ||
- | public partial class CustomDwgEntity : DwgEntity, IConstructionModelHolder, IPointObject | + | public class CustomDwgEntity : DwgEntity, IPointObject |
{ | { | ||
- | public const string PARENT_SMDX = "SmdxCustomVolumeElement"; | + | public const string PARENT_SMDX = "SmdxElement"; |
private ImElement m_Element; | private ImElement m_Element; | ||
- | private GeometryModelsCache m_Cache; | ||
private Vector3D m_Position; | private Vector3D m_Position; | ||
private Vector3D m_Normal = new Vector3D(0, 0, 1); | private Vector3D m_Normal = new Vector3D(0, 0, 1); | ||
- | private Vector3D m_Scale = new Vector3D(1, 1, 1); | ||
private double m_Angle = 0; | private double m_Angle = 0; | ||
private Drawing m_Plan; | private Drawing m_Plan; | ||
- | private int m_Changes; | ||
#region Properties | #region Properties | ||
Строка 61: | Строка 56: | ||
get | get | ||
{ | { | ||
- | return Matrix.CreateExtrudedInsertion(m_Position, m_Scale, m_Normal, m_Angle); | + | return Matrix.CreateExtrudedInsertion(m_Position, Vector3D.One, m_Normal, m_Angle); |
} | } | ||
} | } | ||
Строка 76: | Строка 71: | ||
if (Position != value) | if (Position != value) | ||
{ | { | ||
- | BeginChange(); | + | m_Position = value; |
- | try | + | |
- | { | + | |
- | m_Position = value; | + | |
- | } | + | |
- | finally | + | |
- | { | + | |
- | EndChange(); | + | |
- | } | + | |
} | } | ||
} | } | ||
} | } | ||
- | |||
- | [Browsable(false)] | ||
- | public double Rotation | ||
- | { | ||
- | get | ||
- | { | ||
- | return Angle; | ||
- | } | ||
- | set | ||
- | { | ||
- | Angle = value; | ||
- | } | ||
- | } | ||
- | |||
[Angle] | [Angle] | ||
[DisplayName("Угол поворота")] | [DisplayName("Угол поворота")] | ||
Строка 114: | Строка 87: | ||
if (Angle != value) | if (Angle != value) | ||
{ | { | ||
- | BeginChange(); | + | m_Angle = value; |
- | try | + | |
- | { | + | |
- | m_Angle = value; | + | |
- | } | + | |
- | finally | + | |
- | { | + | |
- | EndChange(); | + | |
- | } | + | |
} | } | ||
} | } | ||
Строка 131: | Строка 96: | ||
get { return m_Position; } | get { return m_Position; } | ||
} | } | ||
- | + | | |
- | [GlobalVector, DisplayName("Масштаб")] | + | |
- | public Vector3D Scale | + | |
- | { | + | |
- | get | + | |
- | { | + | |
- | return m_Scale; | + | |
- | } | + | |
- | set | + | |
- | { | + | |
- | if (Scale != value) | + | |
- | { | + | |
- | BeginChange(); | + | |
- | try | + | |
- | { | + | |
- | m_Scale = value; | + | |
- | } | + | |
- | finally | + | |
- | { | + | |
- | EndChange(); | + | |
- | } | + | |
- | } | + | |
- | } | + | |
- | } | + | |
[DisplayName("3D модель"), ImObjectPropertyProvider(PARENT_SMDX, false)] | [DisplayName("3D модель"), ImObjectPropertyProvider(PARENT_SMDX, false)] | ||
public ImElement Element | public ImElement Element | ||
Строка 170: | Строка 111: | ||
m_Element = value; | m_Element = value; | ||
m_Plan = null; | m_Plan = null; | ||
- | m_Cache = null; | ||
Invalidate(); | Invalidate(); | ||
} | } | ||
Строка 191: | Строка 131: | ||
if (Normal != value) | if (Normal != value) | ||
{ | { | ||
- | BeginChange(); | + | Vector3D position, scale; |
- | try | + | double angle; |
+ | var view1 = Matrix.GetElementView(out position, out scale, out angle); | ||
+ | m_Normal = value; | ||
+ | var view2 = Matrix.GetElementView(out position, out scale, out angle); | ||
+ | if (view1 != view2) | ||
{ | { | ||
- | Vector3D position, scale; | + | m_Plan = null; |
- | double angle; | + | |
- | var view1 = Matrix.GetElementView(out position, out scale, out angle); | + | |
- | m_Normal = value; | + | |
- | var view2 = Matrix.GetElementView(out position, out scale, out angle); | + | |
- | if (view1 != view2) | + | |
- | { | + | |
- | m_Plan = null; | + | |
- | } | + | |
- | Invalidate(); | + | |
- | } | + | |
- | finally | + | |
- | { | + | |
- | EndChange(); | + | |
} | } | ||
+ | Invalidate(); | ||
} | } | ||
} | } | ||
} | } | ||
- | + | | |
- | [Browsable(false)] | + | |
- | public GeometryModelsCache Cache | + | |
- | { | + | |
- | get | + | |
- | { | + | |
- | if (m_Cache == null) | + | |
- | { | + | |
- | if (m_Element != null) | + | |
- | { | + | |
- | var builder = new GeometryModelsCacheBuilder(Position); | + | |
- | m_Cache = builder.Create(m_Element, Matrix); | + | |
- | } | + | |
- | } | + | |
- | return m_Cache; | + | |
- | } | + | |
- | } | + | |
public override bool IsBreakable | public override bool IsBreakable | ||
{ | { | ||
Строка 258: | Строка 173: | ||
get { return TypeExplorer.GetSerializableString(GetType()); } | get { return TypeExplorer.GetSerializableString(GetType()); } | ||
} | } | ||
- | + | | |
- | [Category("Информационная модель"), TypedObjectProvider(null)] | + | |
- | public TypedObject TypedObject | + | |
- | { | + | |
- | get | + | |
- | { | + | |
- | return new CustomElementWrapper(this); | + | |
- | } | + | |
- | } | + | |
[Browsable(false)] | [Browsable(false)] | ||
public BoundingBox3D Bounds3d | public BoundingBox3D Bounds3d | ||
Строка 277: | Строка 183: | ||
Regen(EventArgs.Empty); | Regen(EventArgs.Empty); | ||
} | } | ||
- | var cache = Cache; | + | |
+ | var cache = GetCache(); | ||
if (cache != null) | if (cache != null) | ||
{ | { | ||
Строка 285: | Строка 192: | ||
return bounds; | return bounds; | ||
} | } | ||
- | else | ||
- | { | ||
- | return new BoundingBox3D(); | ||
- | } | ||
- | } | ||
- | } | ||
- | [Browsable(false)] | + | return new BoundingBox3D(); |
- | public bool HasCache3D | + | |
- | { | + | |
- | get | + | |
- | { | + | |
- | return m_Cache != null; | + | |
} | } | ||
} | } | ||
Строка 305: | Строка 201: | ||
{ | { | ||
var matrix = Matrix; | var matrix = Matrix; | ||
- | if (m_Cache != null) | ||
- | { | ||
- | m_Cache.Dispose(); | ||
- | } | ||
- | m_Cache = null; | ||
var plan = GetPlan(1.0); | var plan = GetPlan(1.0); | ||
if ((plan != null) && (plan.Count > 0)) | if ((plan != null) && (plan.Count > 0)) | ||
Строка 332: | Строка 223: | ||
if (model != null) | if (model != null) | ||
{ | { | ||
- | var m = matrix; | + | var element = new Static3DElement( |
- | Vector3D position, scale, normal; | + | m_Element.Name, m_Element.GetObjectType(), |
- | double angle; | + | m_Element.GetProperties().Clone(), |
- | m.GetExtrudedInsertion(out position, out scale, out normal, out angle); | + | model, new ImDocuments(m_Element)); |
- | var e = new CustomDwgEntity(); | + | ExtractEntities(list, matrix, model, element); |
- | e.CopyProperties(this); | + | |
- | e.Position = position; | + | |
- | e.Scale = scale; | + | |
- | e.Normal = normal; | + | |
- | e.Angle = angle; | + | |
- | e.Element = new Static3DElement(m_Element.Name, m_Element.GetObjectType(), m_Element.GetProperties().Clone(), model, new ImDocuments(m_Element)); | + | |
- | e.m_Plan = null; | + | |
- | e.m_Cache = null; | + | |
- | list.Add(e); | + | |
} | } | ||
if (m_Element.IsAssembly) | if (m_Element.IsAssembly) | ||
Строка 352: | Строка 234: | ||
{ | { | ||
var m = item.GetMatrix() * matrix; | var m = item.GetMatrix() * matrix; | ||
- | Vector3D position, scale, normal; | + | ExtractEntities(list, m, model, item.Element); |
- | double angle; | + | |
- | m.GetExtrudedInsertion(out position, out scale, out normal, out angle); | + | |
- | var e = new CustomDwgEntity(); | + | |
- | e.CopyProperties(this); | + | |
- | e.Position = position; | + | |
- | e.Scale = scale; | + | |
- | e.Normal = normal; | + | |
- | e.Angle = angle; | + | |
- | e.Element = item.Element; | + | |
- | e.m_Plan = null; | + | |
- | e.m_Cache = null; | + | |
- | list.Add(e); | + | |
} | } | ||
} | } | ||
Строка 372: | Строка 242: | ||
protected override void OnAssign(DwgEntity source) | protected override void OnAssign(DwgEntity source) | ||
{ | { | ||
- | var model = source as CustomDwgEntity; | + | var entity = source as CustomDwgEntity; |
- | if (model != null) | + | if (entity != null) |
{ | { | ||
- | if (model.m_Element != null) | + | if (entity.m_Element != null) |
{ | { | ||
- | m_Element = model.m_Element.Clone(); | + | m_Element = entity.m_Element.Clone(); |
- | m_Cache = model.m_Cache; | + | m_Plan = entity.m_Plan; |
- | m_Plan = model.m_Plan; | + | m_Position = entity.m_Position; |
- | m_Position = model.m_Position; | + | m_Normal = entity.m_Normal; |
- | m_Normal = model.m_Normal; | + | m_Angle = entity.m_Angle; |
- | m_Scale = model.m_Scale; | + | |
- | m_Angle = model.m_Angle; | + | |
} | } | ||
else | else | ||
Строка 394: | Строка 262: | ||
protected override void OnTransform(Matrix matrix) | protected override void OnTransform(Matrix matrix) | ||
{ | { | ||
- | BeginChange(); | + | var scale = Vector3D.One; |
- | try | + | (Matrix * matrix).GetExtrudedInsertion(out m_Position, out scale, out m_Normal, out m_Angle); |
- | { | + | |
- | (Matrix * matrix).GetExtrudedInsertion(out m_Position, out m_Scale, out m_Normal, out m_Angle); | + | |
- | } | + | |
- | finally | + | |
- | { | + | |
- | EndChange(); | + | |
- | } | + | |
} | } | ||
Строка 409: | Строка 270: | ||
m_Position.SaveToStg(node.AddNode("Position")); | m_Position.SaveToStg(node.AddNode("Position")); | ||
m_Normal.SaveToStg(node.AddNode("Normal"), Vector3D.UnitZ); | m_Normal.SaveToStg(node.AddNode("Normal"), Vector3D.UnitZ); | ||
- | m_Scale.SaveToStg(node.AddNode("Scale"), Vector3D.One); | ||
node.AddDouble("Angle", m_Angle, 0.0); | node.AddDouble("Angle", m_Angle, 0.0); | ||
} | } | ||
Строка 436: | Строка 296: | ||
m_Position = Vector3D.LoadFromStg(node.GetNode("Position")); | m_Position = Vector3D.LoadFromStg(node.GetNode("Position")); | ||
m_Normal = Vector3D.LoadFromStg(node.GetNode("Normal"), Vector3D.UnitZ); | m_Normal = Vector3D.LoadFromStg(node.GetNode("Normal"), Vector3D.UnitZ); | ||
- | m_Scale = Vector3D.LoadFromStg(node.GetNode("Scale"), Vector3D.One); | ||
m_Angle = node.GetDouble("Angle", 0); | m_Angle = node.GetDouble("Angle", 0); | ||
} | } | ||
Строка 450: | Строка 309: | ||
{ | { | ||
m_Plan = context.GetSerializable<Drawing>(node.GetInt32("PlanSign")); | m_Plan = context.GetSerializable<Drawing>(node.GetInt32("PlanSign")); | ||
- | } | ||
- | } | ||
- | |||
- | | ||
- | public void BeginChange() | ||
- | { | ||
- | m_Changes++; | ||
- | BeginUpdate(); | ||
- | } | ||
- | |||
- | public void EndChange() | ||
- | { | ||
- | m_Changes--; | ||
- | if (m_Changes == 0) | ||
- | { | ||
- | m_Plan = null; | ||
- | m_Cache = null; | ||
- | Invalidate(); | ||
- | EndUpdate(); | ||
} | } | ||
} | } | ||
Строка 478: | Строка 318: | ||
Regen(EventArgs.Empty); | Regen(EventArgs.Empty); | ||
} | } | ||
- | var cache = Cache; | + | var cache = GetCache(); |
if (cache != null) | if (cache != null) | ||
{ | { | ||
Строка 539: | Строка 379: | ||
return block; | return block; | ||
} | } | ||
- | } | ||
- | </file> | + | public GeometryModelsCache GetCache() |
+ | { | ||
+ | var builder = new GeometryModelsCacheBuilder(Position); | ||
+ | var cache = builder.Create(Element, Matrix); | ||
+ | return cache; | ||
+ | } | ||
- | ==== Обёртка примитива ==== | + | private void ExtractEntities(IList<DwgEntity> list, Matrix matrix, GeometryModel3D model, ImElement element) |
- | + | { | |
- | Обёртка примитива (**Wrapper**) – это объект-посредник между примитивом и инспектором свойств. С его помощью обеспечивается изменение состояния примитива. Класс обёртки описывается внутри класса примитива. | + | Vector3D position, scale, normal; |
- | Создадим класс обёртки. Для удобства работы с кодом, поместим описание класса-обёртки в отдельный файл. Класс должен наследовать абстрактный тип **TypedObjectWrapper**. Перекроем необходимые методы. | + | double angle; |
- | Добавьте в программу новый класс со следующим содержанием: | + | matrix.GetExtrudedInsertion(out position, out scale, out normal, out angle); |
- | + | var e = new CustomDwgEntity(); | |
- | <file csharp CustomDwgEntity.Wrapper.cs> | + | e.CopyProperties(this); |
- | + | e.Position = position; | |
- | public partial class CustomDwgEntity | + | e.Normal = normal; |
- | { | + | e.Angle = angle; |
- | class CustomElementWrapper : TypedObjectWrapper | + | e.Element = element; |
- | { | + | e.m_Plan = null; |
- | private CustomDwgEntity m_Owner; | + | list.Add(e); |
- | + | } | |
- | public CustomElementWrapper(CustomDwgEntity owner) | + | |
- | { | + | |
- | m_Owner = owner; | + | |
- | } | + | |
- | + | ||
- | protected override TypedObject GetTypedObject() | + | |
- | { | + | |
- | return m_Owner.m_Element; | + | |
- | } | + | |
- | + | ||
- | protected override void OnTypeChanged(ImTypeDescriptor dsc) | + | |
- | { | + | |
- | throw new NotSupportedException(); | + | |
- | } | + | |
- | + | ||
- | protected override void OnAddProperty(TypedObject tobj, ImProperty p) | + | |
- | { | + | |
- | m_Owner.BeginUpdate(); | + | |
- | try | + | |
- | { | + | |
- | var properties = tobj.GetProperties(); | + | |
- | properties.Add(p); | + | |
- | tobj.ApplayOverridedProperties(properties); | + | |
- | + | ||
- | m_Owner.m_Cache = null; | + | |
- | m_Owner.m_Plan = null; | + | |
- | m_Owner.Invalidate(); | + | |
- | } | + | |
- | finally | + | |
- | { | + | |
- | m_Owner.EndUpdate(); | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | protected override void OnModifiedProperty(TypedObject tobj, ImProperty p, object value) | + | |
- | { | + | |
- | m_Owner.BeginUpdate(); | + | |
- | try | + | |
- | { | + | |
- | if (tobj.TryGetProperty(p, out var property)) | + | |
- | { | + | |
- | property.Value = value; | + | |
- | tobj.ApplayOverridedProperties(new[] { property }); | + | |
- | } | + | |
- | + | ||
- | m_Owner.m_Cache = null; | + | |
- | m_Owner.m_Plan = null; | + | |
- | m_Owner.Invalidate(); | + | |
- | } | + | |
- | finally | + | |
- | { | + | |
- | m_Owner.EndUpdate(); | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | protected override void OnRemoveProperty(TypedObject tobj, ImProperty property) | + | |
- | { | + | |
- | m_Owner.BeginUpdate(); | + | |
- | try | + | |
- | { | + | |
- | var properties = tobj.GetProperties(); | + | |
- | properties.Remove(property); | + | |
- | tobj.ApplayOverridedProperties(properties); | + | |
- | + | ||
- | m_Owner.m_Cache = null; | + | |
- | m_Owner.m_Plan = null; | + | |
- | m_Owner.Invalidate(); | + | |
- | } | + | |
- | finally | + | |
- | { | + | |
- | m_Owner.EndUpdate(); | + | |
- | } | + | |
- | } | + | |
- | } | + | |
} | } | ||
Строка 671: | Строка 441: | ||
var e = (CustomDwgEntity)entity; | var e = (CustomDwgEntity)entity; | ||
var has_grips = false; | var has_grips = false; | ||
- | var drawing = e.Drawing; | + | var grip = new EntityGrip(((CadView)cadview), entity); |
- | var obj = e.TypedObject; | + | grip.Location = e.Position; |
- | var cadView = (CadView)cadview; | + | var z = e.Position.Z; |
- | foreach (var p in obj.GetAllProperties()) | + | grip.Move += delegate (Vector3D vertex) |
{ | { | ||
- | var grips = TypedPropertyManagerCollection.Current.GetGrips(cadView, drawing, obj, p, e.Matrix); | + | e.Position = new Vector3D(vertex.Pos, z); |
- | if (grips != null) | + | }; |
- | { | + | yield return grip; |
- | foreach (var tg in grips) | + | |
- | { | + | |
- | if (tg.Location.EqualsEps(e.Position)) | + | |
- | { | + | |
- | has_grips = true; | + | |
- | } | + | |
- | yield return tg; | + | |
- | } | + | |
- | } | + | |
- | } | + | |
- | if (!has_grips) | + | |
- | { | + | |
- | var grip = new EntityGrip(((CadView)cadview), entity); | + | |
- | grip.Location = e.Position; | + | |
- | var z = e.Position.Z; | + | |
- | grip.Move += delegate (Vector3D vertex) | + | |
- | { | + | |
- | e.Position = new Vector3D(vertex.Pos, z); | + | |
- | }; | + | |
- | yield return grip; | + | |
- | } | + | |
} | } | ||
| | ||
protected override void OnPaintEntity3d(DwgEntity entity, PaintEntityEventArgs args) | protected override void OnPaintEntity3d(DwgEntity entity, PaintEntityEventArgs args) | ||
+ | { | ||
+ | var e = (CustomDwgEntity)entity; | ||
+ | var dc = args.Pen.DeviceContext; | ||
+ | if (args.Pen.DeviceContext.gContains(e.Bounds3d)) | ||
{ | { | ||
- | var e = (CustomDwgEntity)entity; | + | var cache = e.GetCache(); |
- | var dc = args.Pen.DeviceContext; | + | if (cache != null) |
- | if (!e.HasCache3D) | + | |
{ | { | ||
- | if (dc.Simplify) | + | var pivot = dc.Pivot; |
+ | dc.Pivot = e.Position; | ||
+ | try | ||
{ | { | ||
- | dc.RequestRedraw(); | + | cache.Paint(dc); |
- | return; | + | |
} | } | ||
- | } | + | finally |
- | if (args.Pen.DeviceContext.gContains(e.Bounds3d)) | + | |
- | { | + | |
- | var cache = e.Cache; | + | |
- | if (cache != null) | + | |
{ | { | ||
- | var pivot = dc.Pivot; | + | dc.Pivot = pivot; |
- | dc.Pivot = e.Position; | + | |
- | try | + | |
- | { | + | |
- | cache.Paint(dc); | + | |
- | } | + | |
- | finally | + | |
- | { | + | |
- | dc.Pivot = pivot; | + | |
- | } | + | |
} | } | ||
} | } | ||
} | } | ||
+ | } | ||
public override double? Fire(DwgEntity entity, Ray3D ray) | public override double? Fire(DwgEntity entity, Ray3D ray) | ||
- | { | + | { |
- | var e = (CustomDwgEntity)entity; | + | var e = (CustomDwgEntity)entity; |
- | return e.Fire(ray); | + | return e.Fire(ray); |
- | } | + | } |
} | } | ||
</file> | </file> | ||
- | В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». Команда «insert_custom_entity» предложит пользователю указать точку на плане, выбрать 3D-модель из библиотеки и добавить пользовательский примитив в чертёж активной модели. | + | ==== Команда вставки примитива на план ==== |
+ | |||
+ | В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». Команда «insert_custom_entity» предложит пользователю указать точку на плане, выбрать 3D-модель из библиотеки и добавит пользовательский примитив в чертёж активной модели. 3D-модели будут отфильтрованы в соответствии с константой **PARENT_SMDX** класса **CustomDwgEntity**. В списке будут доступны только те модели, чей smdx-тип унаследован от "SmdxElement". | ||
<file csharp Module.cs> | <file csharp Module.cs> | ||
Строка 767: | Строка 510: | ||
</file> | </file> | ||
+ | {{ :developers:tutorial:custom_entity:tut_custom_entity_1.png?nolink |}} | ||
+ | |||
+ | Теперь необходимо сформировать наш plugin-файл. Заполните его следующим образом. | ||
+ | |||
+ | <file javascript TutorialCustomDwgEntity.plugin> | ||
+ | { | ||
+ | "assemblies": { | ||
+ | "TutorialCustomDwgEntity": { | ||
+ | "assembly": "TutorialCustomDwgEntity.dll, TutorialCustomDwgEntity.ModulePluginHost" | ||
+ | } | ||
+ | }, | ||
+ | |||
+ | "actions": { | ||
+ | "id_insert_custom_entity": { | ||
+ | "cmd": "insert_custom_entity", | ||
+ | "title": "Пользовательский примитив", | ||
+ | "description": "Вставка пользовательского примитива" | ||
+ | } | ||
+ | }, | ||
+ | |||
+ | "menubars": { | ||
+ | "rbproj": { | ||
+ | "items": [ | ||
+ | { | ||
+ | "id": "tutorial_menu", | ||
+ | "title": "Tutorial", | ||
+ | "items": [ | ||
+ | "id_insert_custom_entity" | ||
+ | ] | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </file> | ||
+ | |||
+ | Результатом запуска проекта будет появление в главном меню пункта «Tutorial», с подпунктами, которые будут работать в соответствии с описанными выше алгоритмами. | ||
+ | <note>[[developers:tutorial:tutorialcode|Исходный код]] примера расположен в проекте **"TutorialCustomDwgEntity"**.</note> |