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

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


developers:tutorial:addlayer

Различия

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

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

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
developers:tutorial:addlayer [2019/02/24 19:30]
vasya создано
developers:tutorial:addlayer [2022/03/15 19:14] (текущий)
proxor
Строка 20: Строка 20:
  
 За вывод текста на экран отвечает отдельный класс [[developers:​references:​topomatic.cad.foundation.fontmanager|FontManager]]. Получить его экземпляр можно используя синглтон [[developers:​references:​topomatic.cad.foundation.fontmanager.current|FontManager.Current]]. Для отображения текста на экране необходимо получить требуемый шрифт у экземпляра класса [[developers:​references:​topomatic.cad.foundation.fontmanager|FontManager]] и вызвать у него метод [[developers:​references:​0d4287aafc4aea88565fe81cee5a2730|DrawString]]. За вывод текста на экран отвечает отдельный класс [[developers:​references:​topomatic.cad.foundation.fontmanager|FontManager]]. Получить его экземпляр можно используя синглтон [[developers:​references:​topomatic.cad.foundation.fontmanager.current|FontManager.Current]]. Для отображения текста на экране необходимо получить требуемый шрифт у экземпляра класса [[developers:​references:​topomatic.cad.foundation.fontmanager|FontManager]] и вызвать у него метод [[developers:​references:​0d4287aafc4aea88565fe81cee5a2730|DrawString]].
 +
 +Создайте новую [[developers:​tutorial:​createmodel|модель]] и подключите её к программному комплексу [[http://​www.topomatic.ru|Топоматик Робур]].
 +
 +
 +С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки:​
 +
 +  * [[developers:​references:​topomatic.cad.foundation|Topomatic.Cad.Foundation.dll]] - базовые математические типы и операции
 +  * [[developers:​references:​topomatic.controls|Topomatic.Controls.dll]] - базовые диалоги и таблицы
 +  * [[developers:​references:​topomatic.cad.view|Topomatic.Cad.View.dll]] - видовой экран
 +
 +Реализуйте класс Model.cs, который описывает модель. В данном случае задача модели хранить список точек, введённых пользователем.
 +<code csharp>
 +    //​Класс реализующий структуру данных нашей модели
 +    //для поддержки интерфейса IStateController наследуем от StateControllerObject
 +    class Model : StateControllerObject,​ IStgSerializable
 +    {
 +        private bool m_ReadOnly = false;
 +
 +        public List<​Vector2D>​ Points = new List<​Vector2D>​();​
 +
 +        //флаг только для чтения
 +        public override bool ReadOnly
 +        {
 +            get
 +            {
 +                return m_ReadOnly;
 +            }
 +
 +            set
 +            {
 +                m_ReadOnly = value;
 +            }
 +        }
 +
 +        //​Загрузка из узла
 +        public void LoadFromStg(StgNode node)
 +        {
 +            Points.Clear();​
 +            //При загрузке массива указывается тип составляющих массив значений
 +            var array = node.GetArray("​Points",​ StgType.Node);​
 +            for (int i = 0; i < array.Count;​ i++)
 +            {
 +                Points.Add(Vector2D.LoadFromStg(array.GetNode(i)));​
 +            }
 +        }
 +
 +        //​Сохранение в узел
 +        public void SaveToStg(StgNode node)
 +        {
 +            //​Сохраняем значения в узел
 +            //​Сохраняем массив с указанием типа значений
 +            var array = node.AddArray("​Points",​ StgType.Node);​
 +            for (int i = 0; i < Points.Count;​ i++)
 +            {
 +                Points[i].SaveToStg(array.AddNode());​
 +            }
 +        }
 +    }
 +</​code>​
 +
 +Для отображения модели на видовом экране необходимо создать слой видового экрана. Поместите его в файл ModelLayer.cs.
 +<code csharp>
 +    class ModelLayer : CadViewLayer
 +    {
 +
 +        //для удобства определяем статический метод, позволяющий получить наш слой с видового экрана
 +        public static ModelLayer GetModelLayer(CadView cadView)
 +        {
 +            //​сначала проверяем,​ есть ли наш слой сразу в самом видовом экране
 +            //это возможно,​ если видовой экран создан отдельно и слой расположен прямо на видовом экране
 +            var layer = cadView[ModelLayer.ID] as ModelLayer;
 +            if (layer == null)
 +            {
 +                //​теперь проверяем не находится ли слой в составе нескольких слоёв модели
 +                //это наиболее распространённая ситуация
 +                //для этого мы получаем слой, который содержит внутри все слои всех моделей
 +                var multi = cadView[Consts.ModelsLayer] as MultiLayer;
 +                if (multi != null)
 +                {
 +                    //​после этого получаем текущий слой активной модели
 +                    var active = multi.ResolveActive();​
 +                    //​проверяем его на соответствие нашему слою
 +                    layer = active as ModelLayer;
 +                    if (layer == null)
 +                    {
 +                        //​кроме того возможен вариант,​ что у нашей модели несколько слоев
 +                        //в этом случае они объединяются внутри общего слоя модели,​ который и будет являться активным
 +                        var compound = active as CompoundLayer;​
 +                        if (compound != null)
 +                        {
 +                            layer = compound[ModelLayer.ID] as ModelLayer;
 +                        }
 +                    }
 +                }
 +            }
 +            //если наш слой найден,​ но он заблокирован на редактирование,​ то мы не можем его вернуть
 +            if ((layer != null) && (!layer.ResolveEnable()))
 +            {
 +                return null;
 +            }
 +            return layer;
 +        }
 +
 +        //наша модель
 +        private Model m_Model;
 +
 +        //​класс,​ отвечающий за выделение объектов
 +        private SelectionSet m_SelectionSet;​
 +
 +        public ModelLayer()
 +        {
 +            //в качестве класса,​ отвечающего за выделение объектов мы используем заглушку которая реализует его по умолчанию,​ в этом случае он не выделяет ничего
 +            m_SelectionSet = new DefaultSelectionSet(this);​
 +        }
 +
 +        //Guid нашего слоя
 +        public static readonly Guid ID = new Guid("​{36C745EB-2111-4D44-B4A1-9BE0B7DBD730}"​);​
 +
 +        //​Возвращаем в качестве LayerId ID объявленный выше
 +        public override Guid LayerGuid
 +        {
 +            get
 +            {
 +                return ID;
 +            }
 +        }
 +
 +        //​Возвращаем нашу заглушку
 +        public override SelectionSet SelectionSet
 +        {
 +            get
 +            {
 +                return m_SelectionSet;​
 +            }
 +        }
 +
 +        public override string Name
 +        {
 +            get
 +            {
 +                return "​Слой тестовой модели";​
 +            }
 +        }
 +
 +        public Model Model
 +        {
 +            get
 +            {
 +                return m_Model;
 +            }
 +            set
 +            {
 +                m_Model = value;
 +            }
 +        }
 +
 +        //​Рассчитываем границы слоя
 +        protected override bool OnGetLimits(out BoundingBox2D limits)
 +        {
 +            //Если есть точки в модели
 +            if (m_Model.Points.Count > 0)
 +            {
 +                //​Создаем рамку вокруг первой точки
 +                limits = new BoundingBox2D(m_Model.Points[0],​ m_Model.Points[0]);​
 +                for (int i = 1; i < m_Model.Points.Count;​ i++)
 +                {
 +                    //и добавляем в нее все остальные точки
 +                    limits.AddPoint(m_Model.Points[i]);​
 +                }
 +                return true;
 +            }
 +            //если точек в модели нет, возвращаем пустую рамку
 +            limits = BoundingBox2D.Empty;​
 +            return false;
 +        }
 +
 +        protected override void OnGetSnapObjects(ObjectSnapEventArgs e)
 +        {
 +            //​Поскольку мы не реализуем привязки,​ то здесь мы не делаем ничего
 +        }
 +
 +        protected override void OnPaint(CadPen pen)
 +        {
 +            //​рисуем нашу линию жёлтым цветом
 +            pen.Color = Color.Yellow;​
 +            //​Начинаем рисовать
 +            pen.BeginDraw();​
 +            try
 +            {
 +                //для отрисовки используем возможность нарисовать массив нескольких точек
 +                //Для этого вызываем начало отрисовки массива
 +                pen.BeginArray();​
 +                for (int i = 0; i < m_Model.Points.Count;​ i++)
 +                {
 +                    //​Добавляем точки
 +                    pen.Vertex(m_Model.Points[i]);​
 +                }
 +                //​Заканчиваем отрисовку массива,​ в виде линии
 +                pen.EndArray(ArrayMode.Polyline);​
 +            }
 +            finally
 +            {
 +                //​заканчиваем рисовать
 +                pen.EndDraw();​
 +            }
 +            //в каждой точке пишем номер оранжевым цветом
 +            pen.Color = Color.Orange;​
 +            //​начинаем рисовать
 +            pen.BeginDraw();​
 +            try
 +            {
 +                var font = FontManager.Current.DefaultFont;​
 +                for (int i = 0; i < m_Model.Points.Count;​ i++)
 +                {
 +                    //​пишем номер точки, высотой в 2 еденицы чертежа
 +                    font.DrawString(i.ToString(),​ pen, m_Model.Points[i],​ 0.0, 2.0);
 +                }
 +            }
 +            finally
 +            {
 +                //​заканчиваем рисовать
 +                pen.EndDraw();​
 +            }
 +        }
 +    }
 +</​code>​
 +
 +<​note>​
 +Мы реализовали у слоя статический метод **ModelLayer.GetModelLayer** который позволяет получить наш слой с видового экрана. Такой метод объявлен для большинства стандартных слоёв программного комплекса [[http://​www.topomatic.ru|Топоматик Робур]].
 +</​note>​
 +
 +Поскольку наша модель предназначена для отображения на видовом экране плана, класс редактора необходимо наследовать от [[developers:​references:​topomatic.applicationplatform.core.planmodeleditor|PlanModelEditor]]. Реализуйте редактор модели в файле Editor.cs.
 +
 +<code csharp>
 +//​Класс реализующий редактор нашей модели
 +    class Editor : PlanModelEditor
 +    {
 +        //​Реализация загрузки модели по указанному пути, должна вернуть реализацию класса нашей модели
 +        public override object LoadFromFile(string fullpath)
 +        {
 +            //​создаем экземпляр класса модели
 +            var model = new Model();
 +            //если fullpath null - то необходимо просто вернуть экземпляр класса модели,​ без загрузки данных
 +            if (fullpath != null)
 +            {
 +                //​создаем файловый поток
 +                using (var stream = new FileStream(fullpath,​ FileMode.Open,​ FileAccess.Read,​ FileShare.Read))
 +                {
 +                    //​создаем документ для работы с Topomatic.Stg
 +                    var document = new StgDocument();​
 +                    //​загружаем документ из потока в бинарном виде
 +                    document.LoadFromStreamAsBinary(stream);​
 +                    //​загружаем данные нашей модели из документа
 +                    model.LoadFromStg(document.Body);​
 +                }
 +            }
 +            //​всегда возвращаем экземпляр модели
 +            return model;
 +        }
 +
 +        //​Реализация сохранения модели по указанному пути
 +        public override void SaveToFile(object model, string fullpath)
 +        {
 +            //в качестве параметра model приходит наша модель данных
 +            var m = model as Model;
 +            if (m != null)
 +            {
 +                //​создаем файловый поток
 +                using (var stream = new FileStream(fullpath,​ FileMode.Create,​ FileAccess.Write,​ FileShare.None))
 +                {
 +                    //​создаем документ для работы с Topomatic.Stg
 +                    var document = new StgDocument();​
 +                    //​сохраняем данные нашей модели в документ
 +                    m.SaveToStg(document.Body);​
 +                    //​сохраняем документ в потока в бинарном виде
 +                    document.SaveToStreamAsBinary(stream);​
 +                }
 +            }
 +        }
 +
 +        protected override CadViewLayer CreatePlanLayer(IProjectModel model)
 +        {
 +            var m = model.LockRead() as Model;
 +            if (m != null)
 +            {
 +                return new ModelLayer() { Model = m };
 +            }
 +            return null;
 +        }
 +
 +        protected override void ReloadModel(IProjectModel model, EditorResult editorResult)
 +        {
 +            var m = model.LockRead() as Model;
 +            if (m != null)
 +            {
 +                var layer = (ModelLayer)editorResult.PlanLayer;​
 +                layer.Model = m;
 +            }
 +        }
 +
 +        protected override void RemovePlanLayer(IProjectModel model, CadViewLayer layer)
 +        {
 +            var model_layer = layer as ModelLayer;
 +            if (model_layer != null)
 +            {
 +                model_layer.Model = null;
 +            }
 +        }
 +    }
 +</​code>​
 +
 +Обратите внимание,​ что в случае реализации редактора модели в виде наследника от [[developers:​references:​topomatic.applicationplatform.core.planmodeleditor|PlanModelEditor]] нет необходимости перекрывать функцию **Open**, но нужно реализовать функции работающие с вашим видовым слоем - **CreatePlanLayer** и **RemovePlanLayer**.
 +
 +В теле программного модуля,​ кроме [[developers:​tutorial:​createmodel|функций для создания и регистрации модели и редактора]],​ необходимо реализовать функцию для редактирования модели. В нашем случае она будет запрашивать у пользователя [[developers:​tutorial:​dynamicrender|ввод многоугольника из нескольких точек]] и сохранять их в нашу модель.
 +<code csharp>
 +...
 +        [cmd("​edit_pointsmodel"​)]
 +        public void EditModel()
 +        {
 +            var cadView = CadView;
 +            if (cadView != null)
 +            {
 +                var model_layer = ModelLayer.GetModelLayer(cadView);​
 +                if (model_layer != null)
 +                {
 +                    //​список выбранных точек
 +                    var positions = new List<​Vector2D>​();​
 +                    //​делегат для динамической отрисовки
 +                    DrawCursorEvent dynamic_draw = delegate (CadPen pen, Vector3D vertex)
 +                    {
 +                        //если есть точки в списке,​ нужно их нарисовать и нарисовать линию
 +                        //от последней выбранной точки, до текущего положения курсора
 +                        if (positions.Count > 0)
 +                        {
 +                            pen.Color = Color.Lime;
 +                            pen.BeginDraw();​
 +                            try
 +                            {
 +                                for (int i = 1; i < positions.Count;​ i++)
 +                                {
 +                                    pen.DrawLine(positions[i - 1], positions[i]);​
 +                                }
 +                                pen.DrawLine(positions[positions.Count - 1], vertex.Pos);​
 +                            }
 +                            finally
 +                            {
 +                                pen.EndDraw();​
 +                            }
 +                        }
 +                    };
 +                    //​подписываемся на событие отрисовки
 +                    cadView.DynamicDraw += dynamic_draw;​
 +                    try
 +                    {
 +                        Vector3D pos;
 +                        //​просим пользователя указать несколько точек
 +                        while (CadCursors.GetPoint(cadView,​ out pos, "​Укажите точку"​))
 +                        {
 +                            positions.Add(pos.Pos);​
 +                        }
 +                        //если точки заданы,​ то изменяем нашу модель
 +                        if (positions.Count > 0)
 +                        {
 +                            //​получаем её со слоя
 +                            var model = model_layer.Model;​
 +                            //​очищаем точки
 +                            model.Points.Clear();​
 +                            //​добавляем новые точки
 +                            model.Points.AddRange(positions);​
 +                            //​выставляем флаг модификации вручную
 +                            var p = PluginCoreOps.FindModel(model);​
 +                            if (p != null)
 +                                p.Modified = true;
 +                            //​обновляем видовой экран
 +                            cadView.Unlock();​
 +                            cadView.Invalidate();​
 +                        }
 +                    }
 +                    finally
 +                    {
 +                        //​отписываемся от события отрисовки
 +                        cadView.DynamicDraw -= dynamic_draw;​
 +                    }
 +                }
 +            }
 +        }
 +...
 +</​code>​
 +
 +В файле .plugin мы [[developers:​tutorial:​createmodel|описываем и подключаем нашу модель]]. Кроме того добавляем дополнительную команду и пункт меню, предназначенный для редактирования модели. А в контекстном меню модели поддерживаем функционал для её активации.
 +
 +<code javascript>​
 +{
 +  ...
 +  "​actions":​ {
 +    ...
 +    "​id_edit_pointsmodel":​ {
 +      "​cmd":​ "​edit_pointsmodel",​
 +      "​title":​ "​Редактировать активную модель"​
 +    }
 +    ...
 +  },
 +  "​contexts":​ {
 +    ...
 +    "​pointsmodel.context":​ {
 +      "​priority":​ 1001,
 +      "​items":​ [
 +        { "​default":​ "​core.id_activate \"​%0\""​ },
 +        "​$(if,​$(opened,​%0),​core.id_close \"​%0\"​ \"​Скрыть модель\",​core.id_open \"​%0\"​ \"​Показать модель\"​)",​
 +        "​core.id_rmitem \"​%0\"",​
 +        "​core.id_mvitem \"​%0\"",​
 +        "​core.id_dublicate \"​%0\"",​
 +        "​-",​
 +        "​core.id_rmitem \"​%0\""​
 +      ]
 +    }
 +    ...
 +  },
 +  "​menubars":​ {
 +    ...
 +    "​rbproj.test_menu":​ {
 +      "​items":​ [
 +        "​id_edit_pointsmodel"​
 +      ]
 +    }
 +    ...
 +  }
 +  ...
 +}
 +</​code>​
 +
 +В результате мы получим возможность добавлять в проект наши тестовые модели и редактировать их содержимое по команде "​Редактировать активную модель"​ в контекстном меню модели. После изменения наша модель будет отображаться на видовом экране плана.
 +{{ :​developers:​tutorial:​addlayer:​result.png?​direct&​600 |}}
 +
 +<​note>​[[developers:​tutorial:​tutorialcode|Исходный код]] примера расположен в проекте **"​tutorial7"​**.</​note>​
  
developers/tutorial/addlayer.1551036627.txt.gz · Последние изменения: 2021/07/22 14:28 (внешнее изменение)