2026年4月4日土曜日

VSCode で ARES の C# クラスライブラリを作成(1)

はじめにVSCodeにC#開発環境を追加しましょう。

  1. VSCodeを実行し機能拡張から C# Dev Kit をインストールします。
  2. 関連する C# や .NET Install Tool もインストールされます。

以下の作業で、空のフォルダを作り、.Net が利用可能かどうかを確認します。

  1. VSCode のターミナルを開きます。
  2. CD C:\temp と入力して、c:\temp フォルダに移動します。
  3. MD cssample と入力して、cssample フォルダを作成します。
  4. CD cssample と入力して、C:\temp\cssample フォルダに移動します。
  5. dotnet --version と入力して、 .Net がインストールされているかどうかを調べます。

  6.  dotnet new classlib --name sample1 --framework net8.0 と入力して、カレントディレクトリに sample1 という名前のクラスライブラリを新規作成します。ターゲットフレームワークは .Net 8.0 にします。

  7. フォルダを開くで、c:\temp\cssample フォルダを開き、sample1.csproj プロジェクトファイルを開きます。
  8. プロジェクト参照を追加します。

  9. Class1.cs ファイルを開き、コードを追加します。


  10. ビルドします。

  11. 実行はARESからNETLOADコマンドでロードして、CSCIRC1コマンドを実行します。

  12. 実行結果





VSCode で ARES のアプリケーション開発(2)

ARESの設定

VSCodeをARESのデバッガとして利用するには次の設定を行います。

  1. OPTIONSコマンドで、オプションダイアログを開きます。
  2. 「システムオプション」の「LISPデバッガー」を選び、「デバッグの有効化」をチェックします。

  3. オプションダイアログをOKで閉じて設定を保存し、ARESを再起動します。
  4. VSCodeやLISP Extensionがインストールされていなかったら、インストールするように指示されます。

デバッグの開始

VSCodeでソースコードを記述し、ソースファイルを C:\Temp\Hello.lsp として保存します。

実行メニューのデバッグの開始を選ぶと、コマンドパレットが表示されて、"Graebert Lisp Debugger: Attach" と "Grabert Lisp Debugger: Launch" が表示されます。アタッチは起動中のARESでコードを実行します。Launch は ARES を起動してコードを実行します。

アタッチを選ぶとリストから起動中のARESを選択できます。
デバッグコンソールにプログラムロード成功という表示がでました。

ARES側でAPPLOAD[アプリケーションのロード]コマンドでソースコードをロードします。
ARES側で定義した LISP コマンド LSPHELLO を実行します。
VSCode側で、LISP コマンドの入り口で止まります。
1行目の家形はコードの実行位置です。
2行目の赤い丸はブレークポイントです。
ツールバーのボタンは左から
実行(F5) は処理の終わりまたはブレークポイントまで実行します。
ステップ実行(F10) は次の行まで実行します。
ステップイン(F11) はユーザー定義関数の中に入ります。
ステップアウト(Shift+F11) は現在の関数の最後まで進み元の関数の次の行で止まります。
再起動 (CTRL+F5)は処理を再開します。
切断(SHFT+F5)は処理を中止します。
F5キーにより、ブレークポイントで止まりました。

さらにF5キーを押すことでLISPコマンド LSPHELLOは終了しました。

ブレークポイントで停止

エディタで vla-AddCircle ポインタの行(38行目)にブレークポイントを設定します。
エディタとARESそれぞれにプログラムをロードさせたのち、ARES側でLISPコマンド ADDCIRC3 を実行します。
中心と半径を画面上で取得したのち、ブレークポイントで処理が止まります。


デバッグコンソールに変数名 app doc spc などを入力すると、それぞれ IAcadApplication 型のCOMオブジェクト、IAcadDocument 型のCOMオブジェクト、IAcadModelSpace 型のCOMオブジェクトが格納されていることがわかります。
また、左側のParameters (引数) のノードを展開すると、これから実行しようとする関数と引数(もしくは式)と、戻り値が表示されます。

ステップ実行[F10]で関数一つずつ処理をするか、実行[F5]キーで最後まで実行した後に、画面をARESに切り替えると、円を描いたことがわかります。






Visual Studio Codeで ARESのアプリケーション開発(1)

 Microsoft の汎用ソフトウェア統合開発環境の Visual Studio Code を使って、Graebert ARES Commander のカスタマイズをいじる。

Visual Studio Code の入手

Microsoft Store から入手します。


それがだめなら公式ページ(https://code.visualstudio.com) から入手します。


ユーザーインストーラー x64 版を起動した場合は、同意してインストール作業を進めます。

インストールが完了したらVisual Studio Code を起動できます。

起動すると英語なので、機能拡張から Japanese Language Pack をインストールします。
再起動後にメニューや画面が日本語になります。
Windows 用 Git もインストールします。
Git for Windowsのインストールで標準エディタを VSCode に変更します。
Git for Windowsのインストール後、VSCode をインストールすると、バージョン管理の画面が変わります。

Graebert LISP Extension の入手

機能拡張の検索ボックスに Graebert と入力してフィルタボタンを押すと Graebert LISP Extension が表示されるので、インストールします。


Graebert LISP Extension の概要

LISPとDCL言語のエディタとしての機能は以下の通りです。
  1. 構文強調表示
  2. スニペットによる補完
  3. 閉カッコの補完と対のカッコの強調表示(Smart bracket)
  4. コメント化、コメント解除  
  5.  自動補完 
  6.  関数定義への移動
  7.  多言語化
  8.  LISP コード保護 
  9. 見出しの追加と変更
  10. 矩形範囲の挿入
  11. オンラインヘルプ
  12. 現在のLISPファイルの読み込み
LISPとDCL言語のデバッガとしての機能は以下の通りです。
    1.  起動している ARES にアタッチする
    2.  ブレークポイントの設定
    3.  ステップ実行
    4.  変数と値を表示
    5.  デバッグコンソール
    6.  ユーザー入力時にARESをアクティブにする
    ARES LISP関数のポップアップヘルプなど便利なコードエディタとして使ってみて、ゆくゆくはデバッガ機能にも挑戦するのがよいと思われます。
     LISP コード保護機能によってLISPのソースコードを暗号化し、暗号化したプログラムを配布することも可能です。これによりエンドユーザーによる改竄やノウハウの流出を防ぎます。
    復号機能はないので、元のソースコードをなくさないようにしてください。






    2025年4月23日水曜日

    Gitリポジトリの一括更新

     こんなバッチファイルはいかがでしょうか。

    REM gitall.bat - update repositries.

    for /D %%i in (*.*) do pushd %%i & git stash & git pull & popd

    コマンドプロンプトに打ち込むなら %%i ではなく %i なので、こうなります。

    for /D %i in (*.*) do pushd %i & git stash & git pull & popd


    2024年7月3日水曜日

    ARESのトリニティ(三位一体)

     ARESのトリニティ戦略、どこがトリニティなんでしょう。

    まずはデスクトップCADが、WindowsにもMacにもLinux版もあるというトリニティ。

    デスクトップCADと、モバイルCAD(ARES Touch)と、ブラウザとサーバーCAD(ARES Kudo)のトリニティ。

    売り切りのスタンドアローンライセンスと、1〜3年間のバージョンアップ権付きのライセンスと、毎月〜毎年払うサブスクリプションもそうかもしれない。

    2024年6月30日日曜日

    Qt 5.15 をソースからビルドする

     Qt for Windows - Building from Source-5/windows-building.html

    QT SDK の準備

    商用ライセンスの Qt を持っています。Qtのインストーラーに目的のバージョンがあります。→ インストーラーからインストールしてください。

    オープンライセンスの Qt のインストーラーに目的のバージョンがあります。 → インストーラーからインストールしてください。

    ※ Visual Studio 2022 でビルドするときは、Visual Studio 2019 の SDK でも大丈夫。

    目的のバージョンがインストーラーからインストールできません。→ 商用ライセンスのライセンスファイルを含めてソースコードからビルドします。

    目的のバージョンがインストーラーからインストールできません→ オープンソース版としてソースコードからのビルドします。

    QT オープンソース版のライセンスについて

    GPL か、LGPLv3 ということになります。

    GPL の場合、ソースコードを公開してオープンソースコミュニティに貢献する。

    LGPL の場合、一定の条件を満たせば、ソースコードを公開する必要はない。
    簡単にいうと、EXE を作って配ったり売ったりするならソースコードも公開しないとダメということになります。

    特に何もいじることなく

    ビルドは成功した。Qt5Core.dll などがあるフォルダにパスを通せば、Linguest.exe やら Designer.exe が動いたのでこれでいいのであろう。
    フォルダ構成はARESのビルドで使っているのと大分違う。
    バラバラになっている BINフォルダ LIBフォルダ INCLUDEフォルダをひとまとめにする必要はある。以前は、QtビルドするのにPerl入れろだのPython入れろだのなんだの言われて閉口したが、今は美しいな。






    2024年6月27日木曜日

    緯度経度とCAD座標

     ARESマッププラグインでGEOマップを挿入するとGEODATAオブジェクトが用意されます。

    GEODATAオブジェクトが利用可能なときは、transformToLonLatAlt() や transformFromLonLatAlt() で緯度経度とXYの変換が可能です。

    #include "stdafx.h"
    #include "FXHeaders.h"	// ほとんどのCFxのヘッダが入っている
    #include "DbGeoData.h"  // GEODATA オブジェクト
    
    //===========================================================
    //  JDTESTCmd Class
    //===========================================================
    int JDTESTCmd::Execute(CFxCommandContext* pCmdCtx)
    {
    	CFxDocumentPtr doc = pCmdCtx->GetFxDocument();
    	CFxUserIO* io = doc->GetFxUserIO();
    	CFxDatabasePtr db = doc->GetFxDatabase();
    	CFxString prompt;
    	OdResult rt;
    	// 座標系が用意できているか
    	OdDbObjectId geoid;
    	if (oddbGetGeoDataObjId(db, geoid) != eOk)
    	{
    		io->Write(L"\nNo GEODATA.");
    		return RTNORM;
    	}
    	OdDbGeoDataPtr geodata = geoid.safeOpenObject();
    	OdGePoint3d p1;
    	OdGePoint3d p2;
    	int rc = io->GetPoint(L"\n位置を指定 : ", nullptr, nullptr, &p1);
    	if (rc == RTNORM)
    	{
    		rt = geodata->transformToLonLatAlt(p1, p2);
    		prompt.format(L"\n(%f,%f,%f) - (%f,%f,%f) ", p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
    		io->Write(prompt);
    		OdError e(rt);
    		io->Write(e.description());
    	}
    	rc = io->GetString(false, L"\n経度,緯度を指定 : ", L"", &prompt);
    	if (rc == RTNORM)
    	{
    		rc = io->GetUnitsFormatter()->StringToPoint(p1, prompt);
    		if (rc == RTNORM)
    		{
    			rt = geodata->transformFromLonLatAlt(p1,p2);
    			prompt.format(L"\n(%f,%f,%f) - (%f,%f,%f)", p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
    			io->Write(prompt);
    			OdError e(rt);
    			io->Write(e.description());
    		}
    	}
    	return RTNORM;
    }

    transformFromLonLatAlt() の戻り値 XYZ の Z がおかしいとき(緯度の値がそのまま入っていることがある)は無視してください。

    緯度経度とCAD座標

    ARES マッププラグインは、ESRIやTeigaのマップソリューションを利用しています。

    C#のカスタムアプリケーションから緯度経度からCAD座標への相互変換を利用する方法を紹介します。

    マッププラグインのGEOマップを有効にして

    GEODATA オブジェクトを図面に挿入し、座標変換を利用可能にします。

    C++ではGEODATAクラスの座標変換APIが利用できますが、ARESのC#にはGEODATAクラスがありませんでした。しかしPOSITIONMARKER図形クラスはあるのでそれを使って座標変換します。

    このプログラムは、POSITIONMARKER 図形を図面に追加して、緯度経度を読み取ったり、緯度経度を設定してXY値を読み取っています。

    using Teigha.ApplicationServices;
    using Teigha.DatabaseServices;
    using Teigha.EditorInput;
    using Teigha.Geometry;
    using Teigha.Runtime;
    using CADException = Teigha.Runtime.Exception;
    
    namespace geodata
    {
        public class Class1
        {
            [CommandMethod("TESTCS")]
            public void cmdTestCS()
            {
                var doc = Application.DocumentManager.MdiActiveDocument;
                var ed = doc.Editor;
                var db = doc.Database;
                try
                {
                    var id = db.GeoDataObject;
                    ed.WriteMessage("\nGEODATA [{0}]", id.Handle.ToString());
                }
                catch (CADException)
                {
                    ed.WriteMessage("\nNo GEODATA.");
                    return;
                }
                var ret = ed.GetPoint("Specify location");
                if(ret.Status != PromptStatus.OK )
                {
                    return;
                }
                var model = db.CurrentSpaceId.GetObject(OpenMode.ForWrite) as BlockTableRecord;
                GeoPositionMarker marker = new GeoPositionMarker();
                marker.Position = ret.Value;
                model.AppendEntity(marker);
                Point3d rts = marker.GeoPosition;
                ed.WriteMessage("\n{0} -> {1}", ret.Value, rts);
                var ret2 = ed.GetString("経度,緯度を入力");
                if (ret2.Status == PromptStatus.OK)
                {
                    string text = ret2.StringResult;
                    int len = text.IndexOf(",");
                    double lon = System.Convert.ToDouble(text.Substring(0, len));
                    double lat = System.Convert.ToDouble(text.Substring(len + 1));
                    Point3d geo = new Point3d(lon,lat,0);
                    marker.GeoPosition = geo;
                    rts = marker.Position;
                    ed.WriteMessage("\n{0} -> {1}", geo, rts);
                }
                marker.Erase();
            }
        }
    }

    緯度経度からXYZに変換したときに、 Z がおかしいとき(緯度の値がそのまま入っていることがある)は無視してください。

    実行結果

    : TESTCS
    GEODATA [10E]
    Specify location: »
    (15086629.5460905,4121448.60999969,0) -> (135.525499071023,34.6871623638417,0)
    経度,緯度を入力: » 135.5255,34.6871
    (135.5255,34.6871,0) -> (15086629.6495038,4121440.16715828,34.6871)


    2024年6月18日火曜日

    コマンドの横取り

     ARESのログファイルは実行したコマンド名しか記録しません。コマンド履歴ウィンドウの内容を取得する方法があれば便利です。

    カスタムコマンドを CFx (C++)で作成してみました。

    準備

    1. 信頼できるフォルダに TeeCommand_24.7_17.tx を置いてください。
    2. アドインとしてアプリケーションを追加します。

    使い方

    1. TEEコマンドを実行します。
    2. 実行するファイル名を指定します。
    3. 出力先のファイル名を指定します。そのままでよければEnterを押します。
    4. コマンドが実行され、正常終了、キャンセルに関わらず、コマンドの出力内容がファイルに出力されます。

    プログラムの説明

    teecommand.h

    class TeeCommand : public CFxCommand, CFxOutputDevice
    {
    public:
    	virtual const OdString groupName() const { return "TEE_GROUP_NAME"; }
    	virtual const OdString globalName() const { return "_TEE"; }
    	virtual const OdString localName() const { return "TEE"; }
    	virtual int Execute(CFxCommandContext* pCmdCtx);
    
    	virtual void CommandOutput(const CFxString& message, const CFxDocument* document);
    	virtual void SystemOutput(const CFxString& message, const CFxDocument* document);
    
    protected:
    	TeeCommand(void) {}
    	~TeeCommand(void) {}
    private:
    	//QString getCoordinates(const OdGePoint3dArray& inp);
    	QStringList m_output;
    	int m_prec;
    };

    teecommand.cpp

    void TeeCommand::CommandOutput(const CFxString& message, const CFxDocument* document)
    {
        m_output.append(message);
    }
    
    void TeeCommand::SystemOutput(const CFxString& message, const CFxDocument* document)
    {
        //m_output.append(message);
    }
    
    int TeeCommand::Execute(CFxCommandContext* pCmdCtx)
    {
        CFxHostAppServicesPtr svc = GetFxSystemServices()->GetHostAppServices();
        CFxDocumentPtr doc = pCmdCtx->GetFxDocument();
        CFxDatabasePtr db = doc->GetFxDatabase();
        CFxUserIO* io = doc->GetFxUserIO();
        m_output.clear();
        // Specify command.
        CFxString command;
        CFxString prompt = io->GetPrompt(L"Command name");
        int rc = io->GetString(false, prompt, L"", &command);
        if (rc != RTNORM)
            return RTNORM;
        // Specify filename.
        QFileInfo fi;
        if (db->getDWGTITLED())
        {
            fi.setFile(QString::fromUtf16(db->getFilename().c_str()));
        }
        else
        {
            fi.setFile(
                QString::fromUtf16(svc->getMYDOCUMENTSPREFIX().c_str()),
                QString::fromUtf16(db->getDWGNAME().c_str())
            );
        }   
        CFxString inputname = QString("%1/%2.txt").arg(fi.absolutePath()).arg(fi.completeBaseName());
        CFxString filename;
        prompt = io->GetPromptString(L"File name", &inputname);
        rc = io->GetString(true, prompt, inputname, &filename);
        if (rc != RTNORM)
            return RTNORM;
        // Run command
        GetFxSystemServices()->AddOutputDevice(this);
        OdResBufPtr cmd = OdResBuf::newRb(OdResBuf::kRtString, command.wide_strU());
        GetFxSystemServices()->SendStringToExecute(nullptr, cmd);
        GetFxSystemServices()->RemoveOutputDevice(this);
        // Write file
        QFile fOut(filename);
        if (fOut.open(QFile::WriteOnly | QFile::Text)) 
        {
            QTextStream s(&fOut);
            s.setCodec("shift-jis");
            for (int i = 0; i < m_output.size(); ++i)
            {
                s << m_output.at(i);
            }
            s.flush();
            fOut.close();
        }
        else 
        {
            io->Write(L"File open error.\n");
        }
        return RTNORM;
    }
    • 最初の GetString( )でコマンド名を入力します。最初の引数が false なのでスペースで入力が終了します。
    • Qt のQFileInfo クラスはディレクトリ、ファイル、拡張子を処理するのに便利なクラスです。
    • 保存済みの図面の場合は CFxDatabase::getFilename() にDWGファイルの完全パスがあるのでそれを使い、未保存の図面の場合はシステム変数 MYDOCUMENTPREFIX と DWGNAME からファイル名を生成します。
    • 最初の GetString( )でファイル名を入力します。最初の引数が true なのでEnterで入力が終了し、ファイル名にスペースを含めることが可能です。
    • AddOutputDevice() でコマンド出力内容の横取りが開始します。
    • SendStringToExecute() でコマンドをただちに実行して、終了まで待ちます。リザルトバッファにコマンドの追加の引数が指定できますが、足りない場合はユーザー入力待ちになります。
    • RemoveOutputDevice() でコマンド出力内容の横取りを終了します。
    • Qtの QFile クラス、QTextStream クラスによってテキストファイルを出力しています。setCodec() によって出力する文字コードをシフトJIS (日本語)に切り替えています。setCodec() がないとユニコード(UTF-8)での出力になります。
    • コマンド出力内容を横取りするためには、CFxOutputDevice クラスを継承する必要があります。TEE コマンドは、CFxCommand と CFxOutputDevice クラスを継承しているのでコマンド出力内容を横取りできるコマンドになります。
    • CFxOutputDevice クラスを継承すると、commandOutput() と systemOutput() を実装する必要があります。今回システムからの出力は不要なので、commandOutput() が呼び出されたら、m_output に文字列をためるようにします。

    ARESのコマンド履歴ウィンドウやコマンドプロンプトウィンドウはQtのウィジェットになっているので text() で内容を取ってくることは可能なのですが、コマンド出力内容が更新されるのは ARES のタイミング次第なので、text() ではうまくいきません。CFx APIに提供されている CFxOutputDevice クラスを利用することで確実にコマンド出力内容を横取りすることができます。

    2024年6月10日月曜日

    案外覚えやすいDXFのグループコード

     案外覚えやすい、DXFのグループコード。行ってみよう。

    基本

    0  データ種類{DXF名)

    1 文字データ

    2 名前(ブロック名など)

    3 コメント、追加の文字データ

    5 図形ハンドル

    6 線種名

    7 スタイル名(文字設定)

    8 画層名

    9 システム変数名

    10 座標値

    38 高度

    39 厚さ

    40 実数値(円の半径等)

    50 角度値(円弧の開始角等)

    60 図形非表示

    62 図形色

    70 整数値(画層のフラグ等)

    90 長整数値

    100 クラス名

    102 リアクター等の目印

    210 押し出し方向

    420 フルカラー

    430 色名

    999 コメント(DXFファイルのみ)

    1000 拡張データ 文字データ

    1001 学長データID

    1002 カツコ

    1003 画像名

    1005 ハンドル(ソフトリンク)

    1010 座標

    1040 実数

    1070 整数

    画層や線種といった各種図形に共通のプロパティは覚えておいて損はない。

    図形などデータベースオブジェクトをDXFファイルやリスト形式で表現するほか、図形の選択条件式としても使います。それはLISP以外でも使います。VBAしかり、c++しかり、.NETでも使います。


    ARESからPowerShellのInvoke-WebRequest を使って適当にファイルをダウンロードしてくる

    何このアタオカな処理はって感じですが... 

    : SHELL

    OS コマンドを指定» powershell.exe Invoke-WebRequest -uri "https://cyberjapandata.gsi.go.jp/xyz/std/1/1/0.png" -outfile "c:\temp\std~1~1~0.png"

    ARESのSHELLコマンドってのが、コマンドプロンプトへの1行分の処理を行って終了を待って戻ってきます。コマンドプロンプトに powershell.exe とするので PowerShell を1行実行です。ここではInvoke-WebRequest というコマンドレットの実行だけなので引数に処理を全部書いちゃいます。 -Uri ダウンロードするファイル -Outfile 出力先 で行けます。

    そこそこ早かったです。

    (2024/06/11 追記)

    スペースを含むパスを引数にしたいときには、シングルクォートで囲う。

    : SHELL

    OS コマンドを指定» powershell.exe Invoke-WebRequest -uri ’https://cyberjapandata.gsi.go.jp/xyz/std/1/1/0.png' -outfile  'C:\Users\cadkh\AppData\Local\Temp\ARES Commander Edition_temp\std~0~0~0.png'

    盲点であった。


    線の太さを一括で変更できますか

    線の太さを一括で変更できますか では、図形をポリラインに変換して任意の線の太さを指定する方法が説明されている。

    いくつかの決まった値しか指定できないが、図形の線の太さプロパティを変更することでも、線を太くすることは可能である。

    1. システム変数 LWDISPLAY を 1 (オン)にして線の太さを画面で表示させる
    2. 図形を複数選んで、プロパティウィンドウで線の太さを変更する

    線の太さを非表示(LWDISPLAY=0)
    線の太さを表示(LWDISPLAY=1)

    図形のプロパティから、ByBlock, ByLayer, 0.00ミリから2.11ミリまでの線の太さを選択できる。

    コマンドラインなら CHPROP [図形のプロパティ]コマンドでも可能。
    複数図形を選択し、LW (線の太さ)オプションを選んで新しい線の太さの値を指定する。
    コマンドラインからは、システム変数 LWUNITS (線の太さの単位)に従って、ミリメートル単位またはインチ単位で新しい線の太さを指定する。


    画層状態管理をLISPで

     画層設定を保存し、別の図面で読み込む方法

    LAYER[画層設定]コマンドでは画層の新規作成、設定の変更、削除を行える。

    複数の画層のフリーズやロックや色の設定をまとめて保存、復元する画層状態管理という機能がある。


    図面に保存した画層状態を拡張子.lasのテキストファイルに出力し他の図面に読み込むことで、画層の設定を他の図面に適用できる。

    現在の画層状態を保存 

    (layerstate-save  name flag [viewport])
    現在の画層状態を name という名前で保存する。
    フラグ flag はどのプロパティを保存するかビット和で指定する。
    オプションのビューポート viewport の図形名を指定すると、指定したビューポートの画層設定を保存する。

    フラグの意味

    1 表示/非表示 設定
    2 フリーズ 設定
    4 ロック 設定
    8 印刷 設定
    16 ビューポート フリーズ初期設定
    32 線色
    64 線種
    128 線幅 

    (layerstate-save "test" 255) は画層のすべての設定を test という名前で保存する。

    現在の画層状態を復元 

    (layerstate-restore  name [viewport flag])
    画層状態 name を図面に復元する。
    オプションのビューポート viewport の図形名を指定すると、指定したビューポートの画層優先設定をして復元する。
    復元フラグ flag は画層状態に含まれていない画層をどう処理するかを指定する。

    復元フラグの意味

    1 含まれていない画層は非表示にする
    2 含まれていない画層はフリーズにする
    4 ビューポートの優先設定にする

    (layerstate-restore "test") で画層状態 test を図面に復元する

    現在の画層状態を書き出し 

    (layerstate-export name file)
    画層状態 name をテキストファイル file に書き出す。
    書き出されたファイルは、他の図面の画層設定に流用できる。
    (layerstate-export "test" "c:/temp/test.las") で c:\temp\test.las ファイルを作成する。

    現在の画層状態を読み込み 

    (layerstate-import file)
    画層状態テキストファイル file を図面に読み込む。
    画層状態名は file の2番目のデータに含まれる。
    (layerstate-import "c:/temp/test.las") で c:\temp\test.las ファイルを読み込む。
    設定が図面に取り込まれるだけで、その復元には (layerstate-restore) の呼び出しが必要。


    2024年6月6日木曜日

    ポリラインの幅をゼロにする

    (IJCADヘルプセンター)ポリラインが太く表示される場合はどうすればよいですか

    選択したポリラインの幅をゼロにするには次のコマンドを作ればよい。

    ;; ポリラインの線幅を0にする
    (defun C:PLZERO ( / ss i n obj)
      (if (setq ss (ssget '((0 . "LWPOLYLINE,POLYLINE"))))
        (progn
          (setq i 0 n (sslength ss))
          (while (< i n )
            (setq obj (vlax-ename->vla-object (ssname ss i)))
            (vla-put-ConstantWidth obj 0.0)
            (setq i (1+ i) obj nil)
          )
          (setq ss nil)
        )
      )
    )

    (ssget)で複数図形選択対話、(sslength)で選択した図形数を取得して、while ループを回して(ssname)で番号指定で図形名を取得するというのが複数図形を処理する鉄板です。覚えてね。

    (vlax-ename->vla-object)でオブジェクトとして取得して、ConstantWidth プロパティを 0.0 に設定することによりポリラインのグローバル幅を0にしています。これだけ。

    図形リストでやろうとすると大変

    図形リストバージョン次の通りになります。わかりやすくするために3つの部分に分けました。
    ;; 図形リストを使ってポリラインの線幅を0にする
    (defun C:PLZERO_EL ( / ss i n el)
      (if (setq ss (ssget '((0 . "LWPOLYLINE,POLYLINE"))))
        (progn
          (setq i 0 n (sslength ss))
          (while (< i n )
            (setq el (entget (ssname ss i)))
            (if (= "LWPOLYLINE" (cdr (assoc 0 el)))
              (plzero0 el)
              (plzero1 el)
            )
            (setq i (1+ i))
          )
          (setq ss nil)
        )
      )
    )

    ;; ライトウェイトポリラインの線幅を0にする
    (defun plzero0 ( el / nl )
      (if (assoc 43 el)
        ;グローバル幅(43)があればそれを変える
        (entmod (subst (cons 43 0.0)(assoc 43 el) el))
        ;開始幅、終了幅を全部0にする必要がある
        (progn
          (while el
            (if (or (= 40 (caar el))(= 41 (caar el)))
              (setq nl (cons (cons (caar el) 0.0) nl))
              (setq nl (cons (car el) nl))
            )
            (setq el (cdr el))
          )
          (entmod (reverse nl))
        )
      )
    )

    ;; ヘビーウェイトポリラインの線幅を0にする
    (defun plzero1 ( el / )
      ;図形リストは POLYLINE,複数のVERTEX,SEQEND
      (while (/= "SEQEND" (cdr (assoc 0 el)))
        ;開始幅(40)と終了幅(41)を0にする
        (if (assoc 40 el)
          (setq el (subst (cons 40 0.0)(assoc 40 el) el))
        )
        (if (assoc 41 el)
          (setq el (subst (cons 41 0.0)(assoc 41 el) el))
        )
        ;リストを更新
        (entmod el)
        ;次の従属図形の図形リストを取得する
        (setq el (entget (entnext (cdr (assoc -1 el)))))
      )
    )

    コマンドの部分では、(vlax-ename->vla-object)が(entget)に変わって図形リストを取得している部分と、図形種類(0)がライトウェイトポリライン "LWPOLYLINE" かどうかで進む関数が分岐している部分が違います。

    ライトウェイトポリラインの変更ではグローバル幅(43)が設定されている場合は、グローバル幅を変更するだけでよいのですが、グローバル幅が設定されていない場合は、図形リストから複数存在する開始幅(40)と終了幅(41)を検出して0.0に変更する必要があります。

    ヘビーウエイトポリラインの変更では、主図形のポリライン図形(POLYLINE)と、従属図形の頂点図形(VERTEX)の開始幅(40)と終了幅(41)を0.0に変更する必要があります。頂点図形を変更するために従属図形の終了マーカー(SEQEND)を検出するwhileループが必要です。

    このように、図形種類によって図形リストが大きく変化する場合、オブジェクトを扱ったほうがわかりやすくなります。


    2024年5月30日木曜日

    うっかり位置情報

    iPhoneで写真から位置情報を削除する に、写真アプリを使って複数の写真や動画からまとめて位置情報を削除する方法も、設定のプライバシーでこれから撮影する写真や動画に位置情報を埋め込まない設定も書いてあった!ありがとう見知らぬ人!

    しかしよ、既定値でオフにしてくれないかな?こういうのは。と思うよね。
    思った人は「いいね👍」

    2024年5月27日月曜日

    マネージドライブラリは今でもクラスライブラリ(.Net Framework) で作成する

    AutoCADのC#,VB.Netのマネージドライブラリ


    • クラスライブラリ(.Net Framework)で作成する
    • ターゲットバージョンは最近は 4.8
    • 拡張子は .dll
    • 参照は、AcMgd.dll, AcCoreMgd.dll, AcDbMgd.dll が必須。後は必要に応じて。
    • Using (Imports)はこの辺が必須。後は必要に応じて。
    • using AutodeskAutoCAD.ApplicationServices;
      using AutodeskAutoCAD.DatabaseServices;
      using AutodeskAutoCAD.EditorInput;
      using AutodeskAutoCAD.Runtime;
    AutoCAD の Core か DataBase の Managed library の と覚えるとよい。

    IJCAD 2024のC#,VB.Netのマネージドライブラリ


    • クラスライブラリ(.Net Framework)で作成する
    • ターゲットバージョンは最近は 4.8
    • 拡張子は .dll
    • 参照は、GcMgd.dll, GcCoreMgd.dll, GcDbMgd.dll が必須。後は必要に応じて。
    • Using (Imports)はこの辺が必須。後は必要に応じて。
    using Itjp.Ijcad.ApplicationServices;
    using Itjp.Ijcad.DatabaseServices;
    using Itjp.Ijcad.EditorInput;
    using Itjp.Ijcad.Runtime;
    GrxCAD の Core か DataBase の Managed library の と覚えるとよい。

    IJCAD 2023のC#,VB.Netのマネージドライブラリ


    • クラスライブラリ(.Net Framework)で作成する
    • ターゲットバージョンは最近は 4.8
    • 拡張子は .dll
    • 参照は、gmap.dll, gmdb.dll が必須。後は必要に応じて。
    • Using (Imports)はこの辺が必須。後は必要に応じて。
    • using GrxCAD.ApplicationServices;
      using GrxCAD.DatabaseServices;
      using GrxCAD.EditorInput;
      using GrxCAD.Runtime;
    GrxCAD の Managed library の Application か DataBase と覚えるとよい。

    ARESのC#,VB.Netのマネージドライブラリ


    • クラスライブラリ(.Net Framework)で作成する
    • ターゲットバージョンは最近は 4.8
    • 拡張子は .dll
    • 参照は、TD_Mgd_バージョン.dll, FxCoreMgd_バージョン.dll が必須。後は必要に応じて。
    • Using (Imports)はこの辺が必須。後は必要に応じて。
    • using Teigha.ApplicationServices;
      using Teigha.DatabaseServices;
      using Teigha.EditorInput;
      using Teigha.Runtime;
    Teigha DWG の Managed library と、Felix Cad の Core の Managed library の と覚えるとよい。(Felix Cad は グレバートが ARES の前に作っていた CAD製品の名前)

    参照するライブラリを変えることと、using 宣言を変えることで、AutoCAD, IJCAD, ARES (おそらく Brics CAD など AutoCAD 系のCADは全部) C# や VB.Net で作成されたマネージドライブラリは動くはずだ。

    参照のときにはローカルコピーをする必要はない。

    2024年5月26日日曜日

    AutoCAD系 カスタマイズについて

     AutoCAD 系 カスタマイズについて

    • プログラミングが必要なもの
    • プログラミングが不要なもの
    今回はプログラミングが必要なものを説明します。

    何が使えるか、何に使うか

    • LISP
    • C#, VB.Net
    • C++
    LISPはCADの組み込みのインタプリタで、コマンドをラッピングして使いやすくしたり、新たにコマンドを作成することも可能です。C++ は CADの高度なカスタマイズが可能です。扱える図形データを追加することも可能です。C#, VB.Net は、多くの人が知っている言語で、外部データベースとの接続など多くのプログラム部品を活用してCADアプリケーションを作成することが可能です。LISPはユーザーインタフェースを扱う部分が弱いので、ダイアログやパレットなどのユーザーインタフェースを利用する場合には C#, VB.Net の利用をお勧めします。

    とりあえずLISP

    AutoCADに最初からあるプログラミング環境であること、他に何も要らないこと、他のプログラミングを使う場合にも有益な基本が学べることから、とりあえずLISPをやってみることをお勧めします。

    Visual Code Editor との連携

    Visual Code Editor を使うと、LISP の組み込み関数のバルーンヘルプや、コード入力補完、整形が便利です。さらにオンラインデバッガとしてCADと連携することも可能です。
    AutoCAD には、Visual LISP IDE という専用の IDE がありましたが、汎用のシェルプログラミングエディタをIDEとして使うことができるようになりました。

      2024年5月25日土曜日

      ライトウェイトポリラインを3Dポリラインに変換するLISPコマンド

       AutoCAD Civil 3D には、2D ポリラインを3D ポリラインに変換するコマンドと、3D ポリラインを2D ポリラインに変換するコマンドがありますが、AutoCAD 他にはありません。

      LISPでライトウェイトポリラインを3Dポリラインに変換するコマンドを作ってみました。

       ;;; ----------------------------------------------------------

      ;;; conv3dpoly.lsp

      ;;; (C) Copyrights 2024 Graebert Japan LLC.

      ;;; ----------------------------------------------------------


      ;;1個のライトウェイトポリラインを変換

      (defun CONV3DPOLY ( en / el la fl i lp )

        ;図形リストを取得する

        (setq el (entget en)

         la (cdr (assoc 8 el))

         fl (cdr (assoc 70 el)))

        ;頂点の数を返す

        (setq i (vlax-curve-getendparam en))

        ;コマンドパラメータの最後はEnterである

        (setq lp '(""))

        ;閉じたポリラインを閉じたポリラインとして処理するとき

        ;(if (/= 0 (logand 1 fl))

        ;  (setq i (- i 1.0) lp '("C"))

        ;)

        ;頂点を最後から最初まで取得する

        (while (not (minusp i))

          ;頂点を前に詰めていく

          (setq lp (cons (vlax-curve-getpointatparam en i) lp))

          (setq i (- i 1.0))

        )

        ;コマンド名を前に詰める

        (setq lp (cons "3dpoly" lp))

        ;画層を切り替え

        (setvar "CLAYER" la)

        ;コマンドを実行

        (apply 'command lp)

        ;ライトウエイトポリラインは削除する

        (entdel en)

      )


      ;;複数のライトウェイトポリラインをまとめて変換

      (defun C:CONV3DPOLY ( / ss cl i n en )

        ; ライトウェイトポリラインのみ取得

        (if (setq ss (ssget '((0 . "LWPOLYLINE"))))

          (progn

            ;画層を元に戻すのに必要

            (setq cl (getvar "CLAYER"))

            ;選択したすべてのライトウェイトポリラインについて

            (setq i 0 n (sslength ss))

            (while (< i n)

              ;図形名を取得

              (setq en (ssname ss i))

              ;3Dポリラインに変換

              (CONV3DPOLY en)

              (setq i (1+ i))

            )

            (setvar "CLAYER" cl)

          )

        )

        (princ)

      )

      次の部分が見どころになります。
      • 特定の図形を複数選択する方法
      • コマンドと関数の切り分け
      • vlax-curve 関数の使用法
      • 可変長のコマンド引数の渡し方


      Visual LISP ~ 図形を画層に振り分けたら線種尺度を設定する

      画層のプロパティとして、線色、線種、線幅、印刷スタイルなどはありますが、線種尺度はありません。線種尺度=ByLayerという設定の代わりになりそうなものを考えてみました。 

      Visual LISP で作成したので、AutoCAD 系の他のCAD でも使えると思います。

      ;;; ----------------------------------------------------------

      ;;; LayLScale.lsp

      ;;; 画層毎に線種尺度を設定する

      ;;; (C) Copyrights 2024 Graebert Japan LLC.

      ;;; ----------------------------------------------------------


      ;; 画層名と線種尺度のペアを設定(いくらでも追加可能)

      (setq #LayLScale '(

          ("MODEL" . 1.0)

          ("MODEL2" . 2.0)

          ("MODEL4" . 4.0)

          ("MODEL8" . 8.0)

          ))


      ;; 線種尺度を書き換えるコールバック関数

      (defun layLscaleReactor( cb data / obj item )

          ; 図形名をVLAオブジェクトに変換

          (if (setq obj (vlax-ename->vla-object (last data)))

              ; VLAオブジェクトは画層と線種尺度が使用できるか

              (if (and (vlax-property-available-p obj 'Layer)

                  (vlax-property-available-p obj 'LinetypeScale T))

                  ; 図形の画層から線種尺度のペアを取得できるか

                  (if (setq item (assoc (vla-get-Layer obj) #LayLScale))

                      ; 線種尺度がペアの設定値と一致していないとき

                      (if (/= (cdr item) (vla-get-LinetypeScale obj))

                          ; 線種尺度を修正する

                          (vla-put-LinetypeScale obj (cdr item))

                      )

                  )

              )

          )

          ; VLAオブジェクトを解放する

          (setq obj nil)

      )


      ;; Visual LISP データベース リアクターを設定

      (vlr-acdb-reactor nil '(

          (:vlr-objectappended . layLscaleReactor)

          (:vlr-objectmodified . layLscaleReactor)

      ))

      使い方は、図面を開いたときに自動的に読み込まれるLISPファイルとしてどこかに登録してください。AutoCADなら、acad2025doc.lsp ファイルに、(load "LayLScale.lsp") と書くとかですね。 

      AutoCAD 2025 のカスタマイズ ことはじめ

      AutoCAD 2025 のカスタマイズに必要な資料はこの辺からアクセス。

      AutoCAD 2025 カスタマイズ オンライン ヘルプ 英語

      https://help.autodesk.com/view/OARX/2025/ENU/

      AutoCAD 2025 カスタマイズ オンライン ヘルプ 日本語

      https://help.autodesk.com/view/OARX/2025/JPN/

      半分くらいは英語のまま提供される

      DXFファイルリファレンスも、オンラインヘルプからアクセス可能。

      AutoCAD 2025でも、DWGのバージョンはAC1032 (AutoCAD 2018相当)のまま。

      メインバージョンはAutoCAD 2018 形式で打ち止めらしい。

      My First AutoCAD Plug-in Overview

      私の最初のAutoCAD プラグインー概要

      https://www.autodesk.com/support/technical/article/caas/tsarticles/ts/6kRFCS0mCalWLwAOpP9pNT.html

      .Net (C#かVB.Net) を使ったアプリケーション作成を1歩ずつ説明するコンテンツ(英語のみ)

      ObjectARX SDK の入手方法

      https://aps.autodesk.com/developer/overview/objectarx-autocad-sdk

      ここから無料で入手可能。以前と異なり名前やメールアドレスを聞かれることもなくなった。

      AutoCAD Mechanical API の入手方法

      https://aps.autodesk.com/developer/overview/autocad-mechanical

      ここから無料で入手可能。

      AutoCAD 2025 の C++アドイン ARX/CRX/DBX の開発では Visual Studio 2022 と Visual C++ が必要になりました。

      C# や VB.Net での開発は、Microsoft .Net Framework 4.8 なので、Visual Studio 2022 必須ではありませんが、C++ での開発が必要なら一緒でよいでしょう。

      Windows 専用の Visual LISP 拡張や、VBA (Visual Basic for Automation) は今でも使えます。

      LISP エディタとしては、Microsoft Visual Code Editor の利用が推奨されてます。

      この流れは止まらないっぽい。

      VSCode で ARES の C# クラスライブラリを作成(1)

      はじめにVSCodeにC#開発環境を追加しましょう。 VSCodeを実行し機能拡張から C# Dev Kit をインストールします。 関連する C# や .NET Install Tool もインストールされます。 以下の作業で、空のフォルダを作り、.Net が利用可能かどうかを...