«Здравствуй елка — Новый Год!» или программируем NanoCAD с помощью Visual Basic .NET

  • Tutorial
Намедни просматривая документацию к NanoCAD API идущую в комплекте с SDK неожиданно обратил внимания на то, что описание членов классов для .NET API и MultiCAD.NET API дано, как на C# так и на Visual Basic. И я подумал: «А ведь это здорово, что есть описание и для VB!»

И хотя если честно я совсем не знаю VB, да и код на старом добром BASIC последний раз видел лет 100 назад, но ведь это же один из языков на котором начинают учить людей азам программирования, поэтому я решил внести свой небольшой вклад в популяризацию программы.

Надо сказать, что на «Хабре» уже есть хорошая статья по применению VB для NanoCAD, там рассматривается связка NanoCAD с Excel и то как она в итоге может облегчить строительное проектирование.

Мы же с Вами решим другую, более простую и праздничную задачу, начертим ёлочку и поздравим пользователя с новым годом. Несмотря на то, что статья посвящена VB, код на C# тоже будет.

А поскольку «Новый год» – праздник затратный то ориентироваться мы будем на бесплатную для коммерческого использования версию NanoCAD 5.1 (но по идее без проблем должно работать и под NC 8.X).

Также не обойдем стороной и пользователей Linux поскольку код на C# с помощью Mono и Wine можно будет на нём скомпилировать и запустить.

Если честно я сам только недавно начал осваивать API NanoCAD и поэтому моя последняя в этом году предпраздничная статья по сложности кода чем-то напоминает теплый ламповый графический исполнитель «Кенгуренок (ROO)», но если вас это не останавливает, то милости прошу под кат…



P.S. Это первая буква слова «Habrahabr» — на большее меня не хватило =)


Поскольку, мое новое хобби, уже превращается в небольшой цикл статей, на всякий случай приведу под спойлером ссылки на все предыдущие статьи:


Для начала как обычно напомню, что я не программист и поэтому не все мои мысли в данной статье могут быть на 100% корректными, а также что с разработчиками NanoCAD я никак не связан, просто по идейным соображениям популяризую отечественную САПР.

Под конец года не хочется плодить гору текста, поэтому статья будет короткой, вот, что мы разберем.

Содержание:
Часть I: введение
Часть II: пишем код на C#
Часть III: пишем код на VB
Часть IV: с Наступающим!

Часть II: пишем код на C#


Как создать новый проект в Visual Studio 2015 для NC 8.5 я уже рассказывал раньше.

В этот раз давайте ради любопытства создадим проект в более легковесной IDE Xamarin Studio (MonoDevelop).

Весь процесс спрячу под спойлер.

Как создать проект C# для NanoCAD 5.1 в IDE Xamarin Studio
Для начала создадим новый проект и выберем библиотеку классов C#



Дадим ему какое-нибудь название



Затем настроим проект нажав по нему ПКМ и выбрав кнопку «параметры»



Выберем версию .Net 3.5



Затем для удобства отладки настроим запуск Нанокада по нажатию клавиши «F5»
(при каждом внесении изменений в код, Нанокад надо будет перезапускать полностью)



Затем загрузим ссылки на библиотеки нам нужны те что отображены справа на картинке



У библиотеки mapimgd не забудьте убрать галочку с пункта «копировать локально»



Ну собственно осталось написать код нажать F5 и посмотреть что всё запускается



Чтобы загрузить вашу библиотеку введите команду Netload в консоль NanoCAD и выберете вашу dll (как правило лежит в папке проекта, например, C:\Users\b\Dev\habr\XMTree\XMTree\bin\Debug)

Для того чтобы каждый раз это не делать
Перейдем по адресу C:\ProgramData\Nanosoft\nanoCAD 5.1\DataRW (у вас может отличаться) и найдем или создадим файл load.config следующего содержания

<root>
    <list>
		<module path="C:\Users\...\bin\Debug\ваша библиотека.dll"/>
    </list>
</root>

После чего библиотеки будут подгружаться автоматически при запуске программы.

Аналогичные манипуляции можно провести и под Linux, там для запуска NanoCAD 5.1 нам понадобится Wine, а для программирования MonoDevelop. Подробнее я описывал в прошлой статье.

К сожалению, там у меня были некоторые проблемы с Wine и цвета NanoCAD местами битые, поэтому наша ёлочка под Linux будет выглядеть так:

Ёлочка под Linux



Код на C# подробно разбирать по кускам не будем, мы практически не делаем ничего нового.

Если кратко, то мы создаем команду, которая рисует полилинии и штрихует их.
Код под спойлером и на GitHub (там же и версия для VB).

Полный код для NC 5.1 на C#
//Use Microsoft .NET Framework 3.5 and old version of MultiCad.NET (for NC 5.1)
//Class for demonstrating the capabilities of MultiCad.NET
//Assembly for the Nanocad 5.1 
//Link mapimgd from Nanocad SDK
//Link System.Windows.Forms and System.Drawing
//The commands: draws a christmas three.
//This code in the part of non-infringing rights Nanosoft can be used and distributed in any accessible ways.
//For the consequences of the code application, the developer is not responsible.

//The code was not tested with NANOCAD 8.X.
// However, it should work, if you  update SDK libraries and include NC 8.X dll

using System.Collections.Generic;
using System.Linq;
using Multicad.Runtime;
using Multicad.DatabaseServices;
using Multicad.Geometry;
using Multicad.DatabaseServices.StandardObjects;
using System.Drawing;
using System.Windows.Forms;

namespace XmasThree
{
    class XmasThree
    {
        [CommandMethod("DXThree", CommandFlags.NoCheck | CommandFlags.NoPrefix)]
        public void DrawXThree()
        {

            Point3d _pntBase;
            Point3d _bufPnt;

            //prompts for installation point entry
            InputJig jig = new InputJig();

            // Get the first box point from the jig
            InputResult res = jig.GetPoint("Select first point:");

            //It works only if input was successful
            if (res.Result == InputResult.ResultCode.Normal)
            {

                // The base point is taken from the entry point (click with mouse)
                _pntBase = res.Point;

                //Draw the outline of the left half of the Christmas tree
                //Create base points for the polyline
                List<Point3d> leftPatrOfThreePoints = new List<Point3d>()
                {
                    new Point3d(_pntBase.X, _pntBase.Y, 0),
                    new Point3d(_pntBase.X-125, _pntBase.Y-154, 0),
                    new Point3d(_pntBase.X-31, _pntBase.Y-137, 0),
                    new Point3d(_pntBase.X-181, _pntBase.Y-287, 0),
                    new Point3d(_pntBase.X-31, _pntBase.Y-253, 0),
                    new Point3d(_pntBase.X-242, _pntBase.Y-400, 0),
                    new Point3d(_pntBase.X-37, _pntBase.Y-400, 0),
                    new Point3d(_pntBase.X-37, _pntBase.Y-454, 0),
                    new Point3d(_pntBase.X, _pntBase.Y-454, 0)
                };

                //Create a polyline (geometry)
                Polyline3d leftPatrOfThree = new Polyline3d(leftPatrOfThreePoints);

                //Create a polyline object and place it on the drawing
                DbPolyline XThreeLeft = new DbPolyline();
                XThreeLeft.Polyline = new Polyline3d(leftPatrOfThree);
                XThreeLeft.Polyline.SetClosed(false);
                XThreeLeft.DbEntity.Color = Color.Green;
                XThreeLeft.DbEntity.AddToCurrentDocument();


                //The right part of the tree is obtained by mirroring the left
                DbPolyline XThreeRight = new DbPolyline();
                XThreeRight.DbEntity.Color = Color.Green;
                XThreeRight.Polyline = (Polyline3d)XThreeLeft.Polyline.Mirror(new Plane3d(_pntBase, new Vector3d(10, 0, 0)));
                XThreeRight.DbEntity.AddToCurrentDocument();

                //From the right and left sides we make a single contour for hatching
                DbPolyline XThreeR = new DbPolyline();
                XThreeR.DbEntity.Color = Color.Green;
                //XThreeR.Polyline = XThreeRight.Polyline.Clone() as Polyline3d; for NC 8.5
                XThreeR.Polyline = XThreeRight.Polyline.GetCopy() as Polyline3d; //FOR NC 5.1
                XThreeR.DbEntity.AddToCurrentDocument();

                List<Point3d> hatchPoints = new List<Point3d>();
                hatchPoints.AddRange(leftPatrOfThreePoints);
                hatchPoints.AddRange(XThreeR.Polyline.Points.Reverse().ToList());

                Polyline3d hatchContur = new Polyline3d(hatchPoints);

                //We will create on the basis of a contour a hatch (geometry) with continuous filling 
                Hatch hatch = new Hatch(hatchContur, 0, 10, true);
                hatch.PattType = PatternType.PreDefined;
                hatch.PatternName = "SOLID";

                //Based on the geometry of the hatch, we create the document object, set its color properties - green
                DbGeometry dbhatch = new DbGeometry();
                dbhatch.Geometry = new EntityGeometry(hatch);
                dbhatch.DbEntity.Color = Color.Green;
                dbhatch.DbEntity.AddToCurrentDocument();

                // if you want you can try to draw balls with circles use
                // DrawThreeBalls(_pntBase);

                //Similarly, make a Christmas tree toy (octagon)
                //red
                _bufPnt = _pntBase.Subtract(new Vector3d(30, 95, 0));
                DbPolyline dbOctoRed = DrawThreeOctogonPl(_bufPnt);//implicit
                dbOctoRed.DbEntity.AddToCurrentDocument();
                Hatch hatchCirkRed = new Hatch(dbOctoRed.Polyline, 0, 1, false);
                hatchCirkRed.PattType = PatternType.PreDefined;
                hatchCirkRed.PatternName = "SOLID";
                DbGeometry dbhatchCirkRed = new DbGeometry();
                dbhatchCirkRed.Geometry = new EntityGeometry(hatchCirkRed);
                dbhatchCirkRed.DbEntity.Color = Color.Red;
                dbhatchCirkRed.DbEntity.AddToCurrentDocument();
                //green
                _bufPnt = _pntBase.Subtract(new Vector3d(-40, 200, 0));
                DbPolyline dbOctoGreen = DrawThreeOctogonPl(_bufPnt);//implicit
                dbOctoGreen.DbEntity.AddToCurrentDocument();
                Hatch hatchCirkGreen = new Hatch(dbOctoGreen.Polyline, 0, 1, false);
                hatchCirkGreen.PattType = PatternType.PreDefined;
                hatchCirkGreen.PatternName = "SOLID";
                DbGeometry dbhatchCirkGreen = new DbGeometry();
                dbhatchCirkGreen.Geometry = new EntityGeometry(hatchCirkGreen);
                dbhatchCirkGreen.DbEntity.Color = Color.LightSeaGreen;
                dbhatchCirkGreen.DbEntity.AddToCurrentDocument();
                //blue
                _bufPnt = _pntBase.Subtract(new Vector3d(-12, 350, 0));
                DbPolyline dbOctoBlue = DrawThreeOctogonPl(_bufPnt);//implicit
                dbOctoBlue.DbEntity.AddToCurrentDocument();
                Hatch hatchCirkBlue = new Hatch(dbOctoBlue.Polyline, 0, 1, false);
                hatchCirkBlue.PattType = PatternType.PreDefined;
                hatchCirkBlue.PatternName = "SOLID";
                DbGeometry dbhatchCirkBlue = new DbGeometry();
                dbhatchCirkBlue.Geometry = new EntityGeometry(hatchCirkBlue);
                dbhatchCirkBlue.DbEntity.Color = Color.Blue;
                dbhatchCirkBlue.DbEntity.AddToCurrentDocument();

                //display the text with congratulations
                MessageBox.Show("I Wish You A Merry Christmas And Happy New Year!");

            }

        }

        public Polyline3d DrawThreeOctogonPl(Point3d _pntB)
        {
            //Create points for an octagon
            List<Point3d> octoPoints = new List<Point3d>()
                {
                    new Point3d(_pntB.X, _pntB.Y, 0),
                    new Point3d(_pntB.X-15, _pntB.Y, 0),
                    new Point3d(_pntB.X-25, _pntB.Y-11.3, 0),
                    new Point3d(_pntB.X-25, _pntB.Y-26.3, 0),
                    new Point3d(_pntB.X-15, _pntB.Y-37.6, 0),
                    new Point3d(_pntB.X, _pntB.Y-37.6, 0),
                    new Point3d(_pntB.X+9.7, _pntB.Y-26.3, 0),
                    new Point3d(_pntB.X+9.7, _pntB.Y-11.3, 0),
                    new Point3d(_pntB.X, _pntB.Y, 0)
                };

            return new Polyline3d(octoPoints);
        }


        //Draws three balls instead of an octagon, can not earn in NanoCAD 8.X
        public void DrawThreeBalls(Point3d _pntB)
        {
            CircArc3d circarcRed = new CircArc3d(_pntB.Subtract(new Vector3d(30, 100, 0)), Vector3d.ZAxis, 15);
            DbCircArc dbCircarcRed = circarcRed;//implicit
            dbCircarcRed.DbEntity.AddToCurrentDocument();
            Hatch hatchCirkRed = new Hatch(circarcRed, 0, 1, false);
            hatchCirkRed.PattType = PatternType.PreDefined;
            hatchCirkRed.PatternName = "SOLID";
            DbGeometry dbhatchCirkRed = new DbGeometry();
            dbhatchCirkRed.Geometry = new EntityGeometry(hatchCirkRed);
            dbhatchCirkRed.DbEntity.Color = Color.Red;
            dbhatchCirkRed.DbEntity.AddToCurrentDocument();

            CircArc3d circarcGreen = new CircArc3d(_pntB.Subtract(new Vector3d(-40, 200, 0)), Vector3d.ZAxis, 15);
            DbCircArc dbCircarcGreen = circarcGreen;//implicit
            dbCircarcGreen.DbEntity.AddToCurrentDocument();
            Hatch hatchCirkGreen = new Hatch(circarcGreen, 0, 1, false);
            hatchCirkGreen.PattType = PatternType.PreDefined;
            hatchCirkGreen.PatternName = "SOLID";
            DbGeometry dbhatchCirkGreen = new DbGeometry();
            dbhatchCirkGreen.Geometry = new EntityGeometry(hatchCirkGreen);
            dbhatchCirkGreen.DbEntity.Color = Color.LightSeaGreen;
            dbhatchCirkGreen.DbEntity.AddToCurrentDocument();


            CircArc3d circarcBlue = new CircArc3d(_pntB.Subtract(new Vector3d(-12, 350, 0)), Vector3d.ZAxis, 15);
            DbCircArc dbCircarcBlue = circarcBlue;//implicit
            dbCircarcBlue.DbEntity.AddToCurrentDocument();
            Hatch hatchCirkBlue = new Hatch(circarcBlue, 0, 1, false);
            hatchCirkBlue.PattType = PatternType.PreDefined;
            hatchCirkBlue.PatternName = "SOLID";
            DbGeometry dbhatchCirkBlue = new DbGeometry();
            dbhatchCirkBlue.Geometry = new EntityGeometry(hatchCirkBlue);
            dbhatchCirkBlue.DbEntity.Color = Color.Blue;
            dbhatchCirkBlue.DbEntity.AddToCurrentDocument();
        }
    }
}

По идее данный код должен заработать и в NC 8.X только надо будет выбрать .NET Framework 4.0 включить в проект mapibasetypes.dll и mapimgd.dll из папки include соответствующей разрядности (x64 или x86) и заменить одну строку (где соответствующий комментарий, а также закомментировать или удалить метод DrawThreeBalls

Получится вот так:

Полный код для NC 8.X на C#
//Use Microsoft .NET Framework 4 and old version of MultiCad.NET (for NC 8.X)
//Class for demonstrating the capabilities of MultiCad.NET
//Assembly for the Nanocad 8.X 
//Link mapimgd and mapibasetypes from Nanocad SDK
//Link System.Windows.Forms and System.Drawing
//The commands: draws a christmas three.
//This code in the part of non-infringing rights Nanosoft can be used and distributed in any accessible ways.
//For the consequences of the code application, the developer is not responsible.

using System.Collections.Generic;
using System.Linq;
using Multicad.Runtime;
using Multicad.DatabaseServices;
using Multicad.Geometry;
using Multicad.DatabaseServices.StandardObjects;
using System.Drawing;
using System.Windows.Forms;

namespace XmasThree
{
    class XmasThree
    {
        [CommandMethod("DXThree", CommandFlags.NoCheck | CommandFlags.NoPrefix)]
        public void DrawXThree()
        {

            Point3d _pntBase;
            Point3d _bufPnt;

            //prompts for installation point entry
            InputJig jig = new InputJig();

            // Get the first box point from the jig
            InputResult res = jig.GetPoint("Select first point:");

            //It works only if input was successful
            if (res.Result == InputResult.ResultCode.Normal)
            {

                // The base point is taken from the entry point (click with mouse)
                _pntBase = res.Point;

                //Draw the outline of the left half of the Christmas tree
                //Create base points for the polyline
                List<Point3d> leftPatrOfThreePoints = new List<Point3d>()
                {
                    new Point3d(_pntBase.X, _pntBase.Y, 0),
                    new Point3d(_pntBase.X-125, _pntBase.Y-154, 0),
                    new Point3d(_pntBase.X-31, _pntBase.Y-137, 0),
                    new Point3d(_pntBase.X-181, _pntBase.Y-287, 0),
                    new Point3d(_pntBase.X-31, _pntBase.Y-253, 0),
                    new Point3d(_pntBase.X-242, _pntBase.Y-400, 0),
                    new Point3d(_pntBase.X-37, _pntBase.Y-400, 0),
                    new Point3d(_pntBase.X-37, _pntBase.Y-454, 0),
                    new Point3d(_pntBase.X, _pntBase.Y-454, 0)
                };

                //Create a polyline (geometry)
                Polyline3d leftPatrOfThree = new Polyline3d(leftPatrOfThreePoints);

                //Create a polyline object and place it on the drawing
                DbPolyline XThreeLeft = new DbPolyline();
                XThreeLeft.Polyline = new Polyline3d(leftPatrOfThree);
                XThreeLeft.Polyline.SetClosed(false);
                XThreeLeft.DbEntity.Color = Color.Green;
                XThreeLeft.DbEntity.AddToCurrentDocument();


                //The right part of the tree is obtained by mirroring the left
                DbPolyline XThreeRight = new DbPolyline();
                XThreeRight.DbEntity.Color = Color.Green;
                XThreeRight.Polyline = (Polyline3d)XThreeLeft.Polyline.Mirror(new Plane3d(_pntBase, new Vector3d(10, 0, 0)));
                XThreeRight.DbEntity.AddToCurrentDocument();

                //From the right and left sides we make a single contour for hatching
                DbPolyline XThreeR = new DbPolyline();
                XThreeR.DbEntity.Color = Color.Green;
                XThreeR.Polyline = XThreeRight.Polyline.Clone() as Polyline3d; // for NC 8.5
                //XThreeR.Polyline = XThreeRight.Polyline.GetCopy() as Polyline3d; //FOR NC 5.1
                XThreeR.DbEntity.AddToCurrentDocument();

                List<Point3d> hatchPoints = new List<Point3d>();
                hatchPoints.AddRange(leftPatrOfThreePoints);
                hatchPoints.AddRange(XThreeR.Polyline.Points.Reverse().ToList());

                Polyline3d hatchContur = new Polyline3d(hatchPoints);

                //We will create on the basis of a contour a hatch (geometry) with continuous filling 
                Hatch hatch = new Hatch(hatchContur, 0, 10, true);
                hatch.PattType = PatternType.PreDefined;
                hatch.PatternName = "SOLID";

                //Based on the geometry of the hatch, we create the document object, set its color properties - green
                DbGeometry dbhatch = new DbGeometry();
                dbhatch.Geometry = new EntityGeometry(hatch);
                dbhatch.DbEntity.Color = Color.Green;
                dbhatch.DbEntity.AddToCurrentDocument();

                // if you want you can try to draw balls with circles use
                // DrawThreeBalls(_pntBase);

                //Similarly, make a Christmas tree toy (octagon)
                //red
                _bufPnt = _pntBase.Subtract(new Vector3d(30, 95, 0));
                DbPolyline dbOctoRed = DrawThreeOctogonPl(_bufPnt);//implicit
                dbOctoRed.DbEntity.AddToCurrentDocument();
                Hatch hatchCirkRed = new Hatch(dbOctoRed.Polyline, 0, 1, false);
                hatchCirkRed.PattType = PatternType.PreDefined;
                hatchCirkRed.PatternName = "SOLID";
                DbGeometry dbhatchCirkRed = new DbGeometry();
                dbhatchCirkRed.Geometry = new EntityGeometry(hatchCirkRed);
                dbhatchCirkRed.DbEntity.Color = Color.Red;
                dbhatchCirkRed.DbEntity.AddToCurrentDocument();
                //green
                _bufPnt = _pntBase.Subtract(new Vector3d(-40, 200, 0));
                DbPolyline dbOctoGreen = DrawThreeOctogonPl(_bufPnt);//implicit
                dbOctoGreen.DbEntity.AddToCurrentDocument();
                Hatch hatchCirkGreen = new Hatch(dbOctoGreen.Polyline, 0, 1, false);
                hatchCirkGreen.PattType = PatternType.PreDefined;
                hatchCirkGreen.PatternName = "SOLID";
                DbGeometry dbhatchCirkGreen = new DbGeometry();
                dbhatchCirkGreen.Geometry = new EntityGeometry(hatchCirkGreen);
                dbhatchCirkGreen.DbEntity.Color = Color.LightSeaGreen;
                dbhatchCirkGreen.DbEntity.AddToCurrentDocument();
                //blue
                _bufPnt = _pntBase.Subtract(new Vector3d(-12, 350, 0));
                DbPolyline dbOctoBlue = DrawThreeOctogonPl(_bufPnt);//implicit
                dbOctoBlue.DbEntity.AddToCurrentDocument();
                Hatch hatchCirkBlue = new Hatch(dbOctoBlue.Polyline, 0, 1, false);
                hatchCirkBlue.PattType = PatternType.PreDefined;
                hatchCirkBlue.PatternName = "SOLID";
                DbGeometry dbhatchCirkBlue = new DbGeometry();
                dbhatchCirkBlue.Geometry = new EntityGeometry(hatchCirkBlue);
                dbhatchCirkBlue.DbEntity.Color = Color.Blue;
                dbhatchCirkBlue.DbEntity.AddToCurrentDocument();

                //display the text with congratulations
                MessageBox.Show("I Wish You A Merry Christmas And Happy New Year!");

            }

        }


        public Polyline3d DrawThreeOctogonPl(Point3d _pntB)
        {
            //Create points for an octagon
            List<Point3d> octoPoints = new List<Point3d>()
                {
                    new Point3d(_pntB.X, _pntB.Y, 0),
                    new Point3d(_pntB.X-15, _pntB.Y, 0),
                    new Point3d(_pntB.X-25, _pntB.Y-11.3, 0),
                    new Point3d(_pntB.X-25, _pntB.Y-26.3, 0),
                    new Point3d(_pntB.X-15, _pntB.Y-37.6, 0),
                    new Point3d(_pntB.X, _pntB.Y-37.6, 0),
                    new Point3d(_pntB.X+9.7, _pntB.Y-26.3, 0),
                    new Point3d(_pntB.X+9.7, _pntB.Y-11.3, 0),
                    new Point3d(_pntB.X, _pntB.Y, 0)
                };

            return new Polyline3d(octoPoints);
        }


    }
}


Часть III: пишем код на VB


Несмотря на то, что процесс создания проекта в Visual Studio 2015 для VB.NET практически полностью идентичен созданию проекта для C# учитывая, то что статью могут читать люди, не имеющие необходимых навыков, все же разберем этот момент подробней.

Для начала создадим новый проект, выберем библиотеку классов VB.NET и выберем .NET Framework 3.5 (для NC 8.X версию 4.0)



Затем нажмем ПКМ на кнопке «ссылки» справа и добавим ссылки на библиотеки, которые вы установили вместе с SDK для любой из версий NanoCAD.

Для этого проекта нам хватит только mapimgd (для NC 8.5 понадобится еще и mapibasetypes).
Также надо будет загрузить стандартные System.Windows.Forms и System.Drawing



Не забудьте удалить галочку со свойства «копировать локально»



Затем настроим проект нажав по нему ПКМ и выбрав кнопку «свойства»
И для удобства отладки настроим запуск Нанокада по нажатию клавиши «F5»



(при каждом внесении изменений в код, Нанокад надо будет перезапускать полностью)

Чтобы загрузить вашу библиотеку введите команду Netload в консоль NanoCAD и выберете скомпилированную dll (как правило лежит в папке проекта, например, C:\Users\b\Dev\habr\XMTree\XMTree\bin\Debug)

Для того чтобы каждый раз это не делать перейдем по адресу C:\ProgramData\Nanosoft\nanoCAD 5.1\DataRW (у вас может отличаться) и найдем или создадим файл load.config следующего содержания:

<root>
    <list>
		<module path="C:\Users\...\bin\Debug\ваша библиотека.dll"/>
    </list>
</root>

После чего библиотеки будут подгружаться автоматически при запуске программы.

Как я уже говорил, VB.NET я не знаю совсем, но как оказалось если немного знать C# и дать проделать всю черновую работу конвертеру кода из C# в VB (например, этому), то для нашей задачи каких-то особых знаний в итоге не потребуется, останется лишь немного подправить.

Полный код команды я размещу под спойлером, а потом разберем его по частям.

Полный код для NC 5.1 на VB.NET
Imports System.Collections.Generic
Imports Multicad.Runtime
Imports Multicad.DatabaseServices
Imports Multicad.Geometry
Imports Multicad.DatabaseServices.StandardObjects
Imports System.Drawing
Imports System.Windows.Forms

Namespace XmasThree
    Class XmasThree
        <CommandMethod("DXThree", CommandFlags.NoCheck Or CommandFlags.NoPrefix)>
        Public Sub DrawXThree()
            Dim _pntBase As Point3d
            Dim _bufPnt As Point3d
            Dim jig As New InputJig()
            'prompts for installation point entry
            Dim res As InputResult = jig.GetPoint("Select first point:")
            If res.Result = InputResult.ResultCode.Normal Then
                'The base point is taken from the entry point (click with mouse)
                _pntBase = res.Point

                'Draw the outline of the left half of the Christmas tree
                'Create base points for the polyline
                Dim leftPatrOfThreePoints As New List(Of Point3d)() From {
                    New Point3d(_pntBase.X, _pntBase.Y, 0),
                    New Point3d(_pntBase.X - 125, _pntBase.Y - 154, 0),
                    New Point3d(_pntBase.X - 31, _pntBase.Y - 137, 0),
                    New Point3d(_pntBase.X - 181, _pntBase.Y - 287, 0),
                    New Point3d(_pntBase.X - 31, _pntBase.Y - 253, 0),
                    New Point3d(_pntBase.X - 242, _pntBase.Y - 400, 0),
                    New Point3d(_pntBase.X - 37, _pntBase.Y - 400, 0),
                    New Point3d(_pntBase.X - 37, _pntBase.Y - 454, 0),
                    New Point3d(_pntBase.X, _pntBase.Y - 454, 0)
                }

                'Create a polyline (geometry)
                Dim leftPatrOfThree As New Polyline3d(leftPatrOfThreePoints)

                'Create a polyline object and place it on the drawing
                Dim XThreeLeft As New DbPolyline()
                XThreeLeft.Polyline = New Polyline3d(leftPatrOfThree)
                XThreeLeft.Polyline.SetClosed(False)
                XThreeLeft.DbEntity.Color = Color.Green
                XThreeLeft.DbEntity.AddToCurrentDocument()

                Dim XThreeRight As New DbPolyline()
                XThreeRight.DbEntity.Color = Color.Green
                XThreeRight.Polyline = DirectCast(XThreeLeft.Polyline.Mirror(New Plane3d(_pntBase, New Vector3d(10, 0, 0))), Polyline3d)
                XThreeRight.DbEntity.AddToCurrentDocument()

                'From the right and left sides we make a single contour for hatching
                Dim XThreeR As New DbPolyline()
                XThreeR.DbEntity.Color = Color.Green
                XThreeR.Polyline = TryCast(XThreeRight.Polyline.GetCopy(), Polyline3d)
                XThreeR.DbEntity.AddToCurrentDocument()

                Dim hatchPoints As New List(Of Point3d)()
                hatchPoints.AddRange(leftPatrOfThreePoints)
                hatchPoints.AddRange(XThreeR.Polyline.Points.Reverse().ToList())

                Dim hatchContur As New Polyline3d(hatchPoints)

                'We will create on the basis of a contour a hatch (geometry) with continuous filling 
                Dim hatch As New Hatch(hatchContur, 0, 10, True)
                hatch.PattType = PatternType.PreDefined
                hatch.PatternName = "SOLID"

                'Based on the geometry of the hatch, we create the document object, set its color properties - green
                Dim dbhatch As New DbGeometry()
                dbhatch.Geometry = New EntityGeometry(hatch)
                dbhatch.DbEntity.Color = Color.Green
                dbhatch.DbEntity.AddToCurrentDocument()

                'Similarly, make a Christmas tree toy (octagon)
                'red
                _bufPnt = _pntBase.Subtract(New Vector3d(30, 95, 0))
                Dim dbOctoRed As DbPolyline = DrawThreeOctogonPl(_bufPnt)
                dbOctoRed.DbEntity.AddToCurrentDocument()
                Dim hatchCirkRed As New Hatch(dbOctoRed.Polyline, 0, 1, False)
                hatchCirkRed.PattType = PatternType.PreDefined
                hatchCirkRed.PatternName = "SOLID"
                Dim dbhatchCirkRed As New DbGeometry()
                dbhatchCirkRed.Geometry = New EntityGeometry(hatchCirkRed)
                dbhatchCirkRed.DbEntity.Color = Color.Red
                dbhatchCirkRed.DbEntity.AddToCurrentDocument()

                'green
                _bufPnt = _pntBase.Subtract(New Vector3d(-40, 200, 0))
                Dim dbOctoGreen As DbPolyline = DrawThreeOctogonPl(_bufPnt)
                dbOctoGreen.DbEntity.AddToCurrentDocument()
                Dim hatchCirkGreen As New Hatch(dbOctoGreen.Polyline, 0, 1, False)
                hatchCirkGreen.PattType = PatternType.PreDefined
                hatchCirkGreen.PatternName = "SOLID"
                Dim dbhatchCirkGreen As New DbGeometry()
                dbhatchCirkGreen.Geometry = New EntityGeometry(hatchCirkGreen)
                dbhatchCirkGreen.DbEntity.Color = Color.LightSeaGreen
                dbhatchCirkGreen.DbEntity.AddToCurrentDocument()

                'blue
                _bufPnt = _pntBase.Subtract(New Vector3d(-12, 350, 0))
                Dim dbOctoBlue As DbPolyline = DrawThreeOctogonPl(_bufPnt)
                dbOctoBlue.DbEntity.AddToCurrentDocument()
                Dim hatchCirkBlue As New Hatch(dbOctoBlue.Polyline, 0, 1, False)
                hatchCirkBlue.PattType = PatternType.PreDefined
                hatchCirkBlue.PatternName = "SOLID"
                Dim dbhatchCirkBlue As New DbGeometry()
                dbhatchCirkBlue.Geometry = New EntityGeometry(hatchCirkBlue)
                dbhatchCirkBlue.DbEntity.Color = Color.Blue
                dbhatchCirkBlue.DbEntity.AddToCurrentDocument()

                MessageBox.Show("I Wish You A Merry Christmas And Happy New Year!!!")
            End If
        End Sub

        Public Function DrawThreeOctogonPl(_pntB As Point3d) As Polyline3d
            'Create points for an octagon
            Dim octoPoints As New List(Of Point3d)() From {
                    New Point3d(_pntB.X, _pntB.Y, 0),
                    New Point3d(_pntB.X - 15, _pntB.Y, 0),
                    New Point3d(_pntB.X - 25, _pntB.Y - 11.3, 0),
                    New Point3d(_pntB.X - 25, _pntB.Y - 26.3, 0),
                    New Point3d(_pntB.X - 15, _pntB.Y - 37.6, 0),
                    New Point3d(_pntB.X, _pntB.Y - 37.6, 0),
                    New Point3d(_pntB.X + 9.7, _pntB.Y - 26.3, 0),
                    New Point3d(_pntB.X + 9.7, _pntB.Y - 11.3, 0),
                    New Point3d(_pntB.X, _pntB.Y, 0)
        }
            Return New Polyline3d(octoPoints)
        End Function



    End Class
End Namespace

Несмотря на то, что код простой давайте на всякий случай разберем подробно и по частям, ведь для VB мы этого еще раньше не делали.

Imports System.Collections.Generic
Imports Multicad.Runtime
Imports Multicad.DatabaseServices
Imports Multicad.Geometry
Imports Multicad.DatabaseServices.StandardObjects
Imports System.Drawing
Imports System.Windows.Forms

Импорт пространств имен библиотеки MultiCAD.NET API чтобы чертить, а также библиотек Windows чтобы вывести окошко и назначить цвета штриховке.

Namespace XmasThree
    Class XmasThree

Определяем пространство имен и имя класса

        <CommandMethod("DXThree", CommandFlags.NoCheck Or CommandFlags.NoPrefix)>
        Public Sub DrawXThreeLeft()

Создаём команду, которая будет потом вводиться в командную строку Нанокад и собственно чертить нашу ёлку.
<CommandMethod(«DXThree»> — имя команды, как мы будем её вызвать из Нанокад, можете задать любое, но лучше по короче, в назначении остальных флагов я не уверен.
Public Sub DrawXThreeLeft() — имя функции (метода) для команды это уже внутренняя логика невидимая для пользователя САПР.

Dim _pntBase As Point3d
Dim _bufPnt As Point3d

Создаем поля класса (переменные), для того чтобы хранить координаты точки вставки и координаты буферной точки вставки для ёлочных украшений.

Dim jig As New InputJig()
Dim res As InputResult = jig.GetPoint("Select first point:")

Создаем новый объект для ввода в консоль и передаем пользователю приглашение кликнуть мышкой по экрану для определения точки вставки.

If res.Result = InputResult.ResultCode.Normal Then
_pntBase = res.Point

Если ввод проведен успешно, то дальше рисуется ёлка, если нет, то не делается ничего.

                Dim leftPatrOfThreePoints As New List(Of Point3d)() From {
                    New Point3d(_pntBase.X, _pntBase.Y, 0),
                    New Point3d(_pntBase.X - 125, _pntBase.Y - 154, 0),
                    New Point3d(_pntBase.X - 31, _pntBase.Y - 137, 0),
                    New Point3d(_pntBase.X - 181, _pntBase.Y - 287, 0),
                    New Point3d(_pntBase.X - 31, _pntBase.Y - 253, 0),
                    New Point3d(_pntBase.X - 242, _pntBase.Y - 400, 0),
                    New Point3d(_pntBase.X - 37, _pntBase.Y - 400, 0),
                    New Point3d(_pntBase.X - 37, _pntBase.Y - 454, 0),
                    New Point3d(_pntBase.X, _pntBase.Y - 454, 0)
                }

Создаем список с точками, которые определят вершины полилинии (левой половины ёлки)

                'Create a polyline (geometry)
                Dim leftPatrOfThree As New Polyline3d(leftPatrOfThreePoints)

                'Create a polyline object and place it on the drawing
                Dim XThreeLeft As New DbPolyline()
                XThreeLeft.Polyline = New Polyline3d(leftPatrOfThree)
                XThreeLeft.Polyline.SetClosed(False)
                XThreeLeft.DbEntity.Color = Color.Green
                XThreeLeft.DbEntity.AddToCurrentDocument()

Вначале создаем геометрию (не видимую на экране) для левой половины ёлки, а потом создаем объект документа, который в итоге командой XThreeLeft.DbEntity.AddToCurrentDocument() разместим в пространстве модели чертежа.

                Dim XThreeRight As New DbPolyline()
                XThreeRight.DbEntity.Color = Color.Green
                XThreeRight.Polyline = DirectCast(XThreeLeft.Polyline.Mirror(New Plane3d(_pntBase, New Vector3d(10, 0, 0))), Polyline3d)
                XThreeRight.DbEntity.AddToCurrentDocument()

Для того, чтобы сделать правую половину ёлки, просто отзеркалим левую (аналог команды mirror в самом NanoCAD). Для этого вызовем у полилинии с левой половиной ёлки метод Mirror и не забудем привести тип к Polyline3d, командой DirectCast.

                Dim XThreeRight As New DbPolyline()
                XThreeRight.DbEntity.Color = Color.Green
                XThreeRight.Polyline = DirectCast(XThreeLeft.Polyline.Mirror(New Plane3d(_pntBase, New Vector3d(10, 0, 0))), Polyline3d)
                XThreeRight.DbEntity.AddToCurrentDocument()

Как ни странно напрямую в справке по MultiCAD.NET API в SDK для NC 5.1 я не нашел отсылок на штриховку (hatch), правда они есть в документации к обычному .NET API, но тем не менее штриховка похоже реализована и в MultiCAD.NET API поэтому приведенный ниже код по крайней мере у меня работает нормально.

                Dim XThreeR As New DbPolyline()
                XThreeR.DbEntity.Color = Color.Green
                XThreeR.Polyline = TryCast(XThreeRight.Polyline.GetCopy(), Polyline3d)
                XThreeR.DbEntity.AddToCurrentDocument()

                Dim hatchPoints As New List(Of Point3d)()
                hatchPoints.AddRange(leftPatrOfThreePoints)
                hatchPoints.AddRange(XThreeR.Polyline.Points.Reverse().ToList())

                Dim hatchContur As New Polyline3d(hatchPoints)

Для начала объединим точки левой и правой половины елки, причем чтобы линия замкнулась в правильном порядке массив вершин для правой половины надо так «перевернуть» чтобы вершины шли в обратном порядке.

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

                'We will create on the basis of a contour a hatch (geometry) with continuous filling 
                Dim hatch As New Hatch(hatchContur, 0, 10, True)
                hatch.PattType = PatternType.PreDefined
                hatch.PatternName = "SOLID"

Создаем геометрию для штриховки, воспользовавшись нашим контуром полной ели. В качестве типа штриховки выбираем сплошную заливку (названия штриховок можно подсмотреть в самом Нанокад выбрав команду «штриховка»).

                Dim dbhatch As New DbGeometry()
                dbhatch.Geometry = New EntityGeometry(hatch)
                dbhatch.DbEntity.Color = Color.Green
                dbhatch.DbEntity.AddToCurrentDocument()

Теперь создадим объект чертежа, который и разместим в пространстве модели, предварительно задав ему зеленый цвет.

Развесим наши ёлочные игрушки. Изначально предполагалось заштриховать шарики, но совет по штриховке круга с форума разработчиков у меня работает только для C# версии кода и только в NC 5.1, поэтому мы будем штриховать 8-ми угольники.

                'Similarly, make a Christmas tree toy (octagon)
                'red
                _bufPnt = _pntBase.Subtract(New Vector3d(30, 95, 0))
                Dim dbOctoRed As DbPolyline = DrawThreeOctogonPl(_bufPnt)
                dbOctoRed.DbEntity.AddToCurrentDocument()
                Dim hatchCirkRed As New Hatch(dbOctoRed.Polyline, 0, 1, False)
                hatchCirkRed.PattType = PatternType.PreDefined
                hatchCirkRed.PatternName = "SOLID"
                Dim dbhatchCirkRed As New DbGeometry()
                dbhatchCirkRed.Geometry = New EntityGeometry(hatchCirkRed)
                dbhatchCirkRed.DbEntity.Color = Color.Red
                dbhatchCirkRed.DbEntity.AddToCurrentDocument()

Весь процесс идентичен тому, что мы делали ранее, единственное отличие, чтобы немного уменьшить объем кода мы создание полилинии для октагона вынесли в отдельный метод DrawThreeOctogonPl
Таких «шариков будет» три (красный, зеленый, синий), думаю отдельно разбирать их нет смысла.

Последнее, что осталось это вывести окошко с поздравлением.

                MessageBox.Show("I Wish You a Merry Christmas and Happy New Year!!!")
            End If
        End Sub

В результате получим следующую картинку.
Для NC 5.1



Для NC 8.1




Часть IV: с Наступающим!


Ну что же может быть кто-то скажет, что мы сейчас сделали бесполезную и никому не нужную «чушь»…

чушь

И что это опять очередная статья для новичков, которой не место на Хабре.

Но, помню что в школе когда нас всех пытались научить программированию, начинали именно с простейших задач по рисованию, чего-либо с помощью Кенгуру, а потом уже давали азы Basic (хотя мне в то время уже больше нравился старый добрый Pascal). Да и что греха таить до сих пор вариации на тему Basic являются одним из доступных способов научить людей программированию, взять хотя бы тот же SmallBasic

Поэтому учитывая, то что NC 5.1 абсолютно бесплатен для любых целей, а для новых версий NanoCAD можно получить лицензию для образовательных учреждений, то думаю старшая школа и учебные заведения среднего профессионального образования вполне могли бы обратить свой взор на Нанокад и на простых примерах объяснить детям как программировать САПР.

Хотя справедливости ради надо отметить, что NC это не единственная САПР которую легко использовать в учебных заведениях и у которой есть открытые API, безусловно можно обратится к тому же «Компасу»

В любом случае желаю всем, счастья и успехов в наступающем 2018 году!
И надеюсь, что разработчики таки подарят нам в 2018 нормальное обновление для бесплатной версии NanoCAD, с новыми API и под новый NET Framework.

P.S. Важно! Чтобы не городить отдельную статью на всякий случай предупрежу людей которые так же как и я ковыряются в API к Nanocad 8.X.

Лично у меня после установки самого последнего обновления Windows 10 в 64 битной версии NanoCAD стали сбоить полилинии (некорректно задается высота). И все написанные ранее команды на C# идут «коту под хвост».

В 32х битной версии всё работает нормально, решение проблемы пока не нашел, так что будьте осторожны перед обновлением Windows 10 если вам это критично.
Поделиться публикацией

Похожие публикации

Комментарии 2
    +1
    Кажется минусуют в основном те, у кого нет новогоднего настроения… стыдно, товарищи!
      +2

      Долой предрассудки! Бейсик тоже язык программирования! Особенно в случае Net.

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое