development of

Tieghaに関する備忘録とおまけ

【IJCAD】ダイアログの前回値を保存を行う方法

ダイアログの前回値はレジストリに書き込める!

ダイアログの値を保持する方法についてはいろいろ考えられますが、IJCAD の .NET API を使用して IJCAD のレジストリに前回値を保存することができます。

UserConfigurationManager クラスの OpenDialogSection メソッドを使用することで、レジストリ内の IJCAD で表示される、各ダイアログのセクションを扱う IConfigurationSection オブジェクトを取得できます。

あとは、 IConfigurationSection インターフェースの、WriteProperty メソッドで前回値をレジストリに書き込むことができて、ReadProperty メソッドでレジストリに書き込まれている前回値の読み込みができます。

サンプルコード

// ウィンドウフォームがロードされたとき
private void SampleForm_Load(object sender, EventArgs e)
{
    // UserConfigurationManagerオブジェクトを取得
    var ucm = GrxCAD.ApplicationServices.Application.UserConfigurationManager;

    // レジストリのセクションを取得
    var section = ucm.OpenDialogSection(this);

    if (section != null)
    {
        // テキストボックスの内容をレジストリから読み込む
        textBox1.Text = System.Convert.ToString(section.ReadProperty(textBox1.Name, ""));

        // チェックボックスの内容をレジストリから読み込む
        checkBox1.Checked = System.Convert.ToBoolean(section.ReadProperty(checkBox1.Name, false));
        checkBox2.Checked = System.Convert.ToBoolean(section.ReadProperty(checkBox2.Name, false));
        checkBox3.Checked = System.Convert.ToBoolean(section.ReadProperty(checkBox3.Name, false));

        // ラジオボタンの内容をレジストリから読み込む
        radioButton1.Checked = System.Convert.ToBoolean(section.ReadProperty(radioButton1.Name, true));
        radioButton2.Checked = System.Convert.ToBoolean(section.ReadProperty(radioButton2.Name, false));
    }
}
// ウィンドウフォームが閉じられるとき
private void SampleForm_FormClosing(object sender, FormClosingEventArgs e)
{
    // UserConfigurationManagerオブジェクトを取得
    var ucm = GrxCAD.ApplicationServices.Application.UserConfigurationManager;

    // レジストリのセクションを取得
    var section = ucm.OpenDialogSection(this);

    if (section != null)
    {
        // テキストボックスの内容をレジストリに書き込む
        section.WriteProperty(textBox1.Name, $"{textBox1.Text}");

        // チェックボックスの内容をレジストリに書き込む
        section.WriteProperty(checkBox1.Name, $"{checkBox1.Checked}");
        section.WriteProperty(checkBox2.Name, $"{checkBox2.Checked}");
        section.WriteProperty(checkBox3.Name, $"{checkBox3.Checked}");

        // ラジオボタンの内容をレジストリに書き込む
        section.WriteProperty(radioButton1.Name, $"{radioButton1.Checked}");
        section.WriteProperty(radioButton2.Name, $"{radioButton2.Checked}");
    }

}

実行結果

f:id:tknmt:20190404105622g:plain

サンプルコードではダイアログのロード時に、レジストリから値を取得して各コントロールに設定し、ダイアログを閉じる時にレジストリへ値を書き込んでいます。
書き込んだ値は下記のレジストキーに追加されます。

HKEY_CURRENT_USER\Software\IntelliJapan\IJCAD Professional\R19\ja-jp\Profiles{プロファイル名}\Dialogs{ダイアログのクラス名}

f:id:tknmt:20190404105751p:plain

IJCAD の API ではブール型が何故か値は扱えなかったので、チェックボックスの値を文字列に変換しています。

【IJCAD Mechanical】パーツ参照を作成する IJCAD偏

IJCAD には残念ながら AutoCAD Mechanical のように、IJCADではメカニカル向けの SDK は、現在公開されていません。

もし SDK が公開されたときには、API で作成したコマンドで、メカニカル特有のオブジェクトの作成ができるようになるかもしれません。  


ICM パーツ参照を作成(C#)

【AutoCAD Mechanical】パーツ参照を作成する その5

これまでの記事の内容を踏まえ、AutoCAD Mechanical 用のコマンドを作成してみました。

ACMでコマンドを実行するとウィンドウが表示され、そこで入力した内容を元に JIS 規格の球平形鋼のブロック参照を作成し、それに関連付いたパーツ参照を作成します。


ACM Customize Sample

プロジェクト一式は、Googleドライブ上に公開しましたので参考にしてみてください。

drive.google.com

【AutoCAD Mechanical】パーツ参照を作成する その4.5

acedSSGet 関数でオブジェクトを選択する

これまでのサンプルコードでは、amiPickメソッドを使用してオブジェクトの選択を行っていました。
今回は Mechanical 特有の関数を使用せずに、 acedSSGet関数を使用してオブジェクトを選択した場合は、どのようにして選択セットからAmiPickObjオブジェクトを取得するのかを調べてみました。

サンプルコード

// オブジェクトを選択
ads_name ss;
ACHAR *promptPtrs[] = {_T("\nパーツ参照追加するオブジェクトを選択"), _T("\n選択を解除するオブジェクトを選択")};
if (acedSSGet(L"_+.:N:S:$", promptPtrs, NULL, NULL, ss) != RTNORM) return;

// 選択セット内の情報を取得
struct resbuf *rb = NULL;
if (acedSSNameXEx(&rb, ss, 0, 0x2) != RTNORM)
{
    acedSSFree(ss);
    return;
}

AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
AcDbTransactionManager *pTransMgr = pDb->transactionManager();

try
{
    AcTransaction *pTrans = pTransMgr->startTransaction();

    AmiPickObj PickObj;
    // acedSSNameXで返されるリザルトバッファからPickObjを取得
    if (amiFillPickObj(rb, Ami::geomKey, PickObj, 1) != Ami::eOk)
    {
        acutRelRb(rb);
        return;
    }
    
    // ピック選択時のリザルトバッファ
    // RTLB      start of entity data sublist 
    // RTSHORT   selection method 
    // RTENAME   picked entity's entity name 
    // RTSHORT   GS marker 
    // RTLB      start of list for pick point 
    // RTSHORT   point descriptor 
    // RT3DPOINT point on pick line (in WCS) 
    // RT3DPOINT vector describing direction of pick line or direction & distance to other end of line segment (only present if viewpoint is not plan WCS) 
    // RTLE      end of list for pick point 
    // RT3DPOINT 
    // RT3DPOINT 
    // RT3DPOINT 
    // RT3DPOINT 
    // RTENAME   
    // RTENAME   
    // RTLE      end of entity data sublist 
    AcGePoint3d pickPoint = asPnt3d(rb->rbnext->rbnext->rbnext->rbnext->rbnext->rbnext->resval.rpoint);
    acutRelRb(rb);

    // パーツ参照を作成
    AcmPartRef *pPartRef = new AcmPartRef();
    pPartRef->setSymbolDefaults(pDb);
    pPartRef->setOrigin(pickPoint);



    // 中略



    pTransMgr->endTransaction();
}
catch (...)
{
    pTransMgr->abortTransaction();
}

※サンプルコードについての補足

標準の関数を使用してオブジェクトの選択を行った場合は、AmiPickObjオブジェクトを取得するには amiFillPickObj関数を使用します。

amiFillPickObj関数は SDK 内ヘルプには、acedSSNameX関数で取得したリザルトバッファから、指定指定されたキータイプのAmiPickObjオブジェクトを返すと説明されています。

中略部分は過去の記事を参考にしてください。

【AutoCAD Mechanical】パーツ参照を作成する その4

パーツ一覧に表示されないパーツ参照

前回、パーツ参照のプロパティの値を設定していきましたが、パーツ一覧から除外は他の値と設定方法が異なるため触れませんでした。

今回は、パーツ一覧から除外の設定を変更していきたいと思います。 f:id:tknmt:20190522150656p:plain  

サンプルコード

// パーツ参照を選択
AmiPickObj PickObj;
if (amiPick(
    _T("\nパーツ参照を選択"),
    AmiKeyType::partKey,
    NULL,
    PickObj,
    Adesk::kFalse) != Acm::eOk) return;

AcDbFullSubentPath subentPath;
AcGePoint3d pickPoint;
AcGeVector3d pickVector;
AcGeMatrix3d viewTrans;
Adesk::Boolean isGhost;

// 選択したときの情報を取得
if (amiGetPickInfo(
    &PickObj,
    subentPath,
    pickPoint,
    pickVector,
    viewTrans,
    isGhost) != Acm::eOk) return;

// パーツ参照のObjectIdを取得
AcDbObjectId partRefId = subentPath.objectIds().first();

// 現在のデータベースを取得
AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();

AcDbObjectId bomId;
bool braekFlg = false;

// 現在の部品表のObjectIdを取得
acmBomMgr->getCurrentBom(bomId, pDb);
// 部品表の項目のイテレータを取得
AcmIterator *pIter = acmBomMgr->newItemIterator(bomId);

while (!pIter->done())
{
    AcmCObjArray<AcDbObjectIdArray> referenceArray;
    AcDbIntArray numItemArray;
    // 部品表の項目で参照されているパーツ参照のObjectIdのコレクションを取得
    acmBomMgr->getItemReferences(pIter->objectId(), referenceArray, numItemArray);
    for each (AcDbObjectIdArray *ids in referenceArray)
    {
        for each (AcDbObjectId id in *ids)
        {
            // 選択したパーツ参照と一致するかどうか
            if (id == partRefId)
            {
                bool data;
                // パーツ参照がパーツ一覧から除外されているかどうかを取得
                if (acmBomMgr->getItemExtendedData(pIter->objectId(), AcmBOMManager::eExcludeFromPartlistState, data) != Acm::eOk)
                {
                    acutPrintf(_T("\nパーツ参照のデータの取得に失敗しました。"));
                    return;
                }
                acutPrintf(_T("\n選択されたパーツ参照はパーツ一覧から除外%s"), data ? _T("されています。") : _T("されていません。"));

                ACHAR answer[255];
                acedInitGet(0, _T("Yes No"));
                if (acedGetKword(_T("\n「パーツ一覧から除外」の設定を変更しますか?: [はい(Y)/いいえ(N)] "), answer) != RTNORM) return;

                if (!_tcscmp(answer, _T("Yes")))
                {
                    // パーツ参照のパーツ一覧から除外の設定を変更
                    if (acmBomMgr->setItemExtendedData(pIter->objectId(), AcmBOMManager::eExcludeFromPartlistState, !data) != Acm::eOk)
                    {
                        acutPrintf(_T("\nパーツ参照のデータの変更に失敗しました。"));
                    }
                }
            }
        }
    }
    pIter->next();
}

AcDbObjectIdArray partListIds;
// パーツ一覧を取得
acmBomMgr->getBomPartsLists(bomId, partListIds);
for each (AcDbObjectId partListId in partListIds)
{
    AcmPartList *pPartList;
    acdbOpenObject(pPartList, partListId, AcDb::kForWrite);
    //パーツ一覧を更新
    pPartList->regen();
    pPartList->close();
}

※サンプルコードについての補足

パーツ一覧から除外の設定を取得するには AcmBOMManager::getItemExtendedDataメソッドを使用し、パーツ一覧から除外の設定を変更するには AcmBOMManager::setItemExtendedDataメソッドを使用します。

これらのメソッドは、特定のデータが部品表の項目に関連付けられているかの取得や設定を行い、パーツ一覧から除外の設定を扱う場合は、いずれも第2引数に AcmBOMManager::ItemDataType列挙型の、eExcludeFromPartlistStateを渡す必要があります。

また、このメソッドを使用して部品表の項目を設定しただけではパーツ一覧が更新されませんので、処理の最後にパーツ一覧を取得して更新を行っています。

【AutoCAD Mechanical】パーツ参照を作成する その3

パーツ参照の情報を設定する

これまでの記事では作成したパーツ参照のプロパティは空欄でした。

【AutoCAD Mechanical】パーツ参照を作成する その1 - development of

パーツ参照を作成する その2 - development of

今回はパーツ参照のコンポーネントのプロパティに値を追加していきます。 f:id:tknmt:20190522144345p:plain

サンプルコード

// パーツ参照を選択
AmiPickObj PickObj;
if (amiPick(
    _T("\nパーツ参照を選択"),
    AmiKeyType::partKey,
    NULL,
    PickObj,
    Adesk::kFalse) != Acm::eOk) return;

AcDbFullSubentPath subentPath;
AcGePoint3d pickPoint;
AcGeVector3d pickVector;
AcGeMatrix3d viewTrans;
Adesk::Boolean isGhost;

// 選択したときの情報を取得
if (amiGetPickInfo(
    &PickObj,
    subentPath,
    pickPoint,
    pickVector,
    viewTrans,
    isGhost) != Acm::eOk) return;

// パーツ参照のObjectIdを取得
AcDbObjectId partRefId = subentPath.objectIds().first();

// パーツ参照のプロパティの値を入力
ACHAR name[512];
if (acedGetString(0, _T("\n名前を入力"), name) != RTNORM) return;
ACHAR descr[512];
if (acedGetString(0, _T("\n説明を入力"), descr) != RTNORM) return;
ACHAR standard[512];
if (acedGetString(0, _T("\n規格を入力"), standard) != RTNORM) return;
ACHAR material[512];
if (acedGetString(0, _T("\n材料を入力"), material) != RTNORM) return;
ACHAR dim[512];
if (acedGetString(0, _T("\n寸法を入力"), dim) != RTNORM) return;
ACHAR units[512];
if (acedGetString(0, _T("\n単位を入力"), units) != RTNORM) return;
ACHAR qty[512];
if (acedGetString(0, _T("\n数量を入力"), qty) != RTNORM) return;

// パーツ参照のプロパティ
const LPCTSTR keyName       = _T("NAME");       // 名前
const LPCTSTR keyDescr      = _T("DESCR");      // 説明
const LPCTSTR keyStabdard   = _T("STANDARD");   // 規格
const LPCTSTR keyMaterial   = _T("MATERIAL");   // 材料
const LPCTSTR keyDim        = _T("DIM");        // 寸法
const LPCTSTR keyUnits      = _T("BOM_UNITS");  // 単位
const LPCTSTR keyQty        = _T("QTY");        // 数量

Adesk::UInt32 numOfItems;
CMapStringToString valueMap;

// 入力した値をセット
valueMap.SetAt(keyName, name);
valueMap.SetAt(keyDescr, descr);
valueMap.SetAt(keyStabdard, standard);
valueMap.SetAt(keyMaterial, material);
valueMap.SetAt(keyDim, dim);
valueMap.SetAt(keyUnits, units);
valueMap.SetAt(keyQty, qty);
numOfItems = _ttoi(qty);

// 部品表にパーツ参照のデータをセット
if(acmBomMgr->setPartData(
    partRefId,
    numOfItems,
    valueMap) != Acm::eOk) return;

※サンプルコードについての補足

パーツ参照には次の表のようなプロパティがあり、各プロパティに対してのキー名が割り振られています。

プロパティ名 キー名
名前 NAME
説明 DESCR
規格 STANDARD
材料 MATERIAL
寸法 DIM
単位 BOM_UNITS
数量 QTY

パーツ参照にパーツの情報を割り当てるには、CMapStringToString クラスを使用して、これらのプロパティのキー名と値のマップを作成し、AcmBOMManager::setPartData メソッドを使用してパーツ参照に値を設定します。

【AutoCAD Mechanical】パーツ参照を作成する その2

オブジェクトに関連付いたパーツ参照を作成する

前回の記事ではただパーツ参照を作成しただけでした。
tknmt.hatenablog.com

今回はオブジェクトに関連付けされ、オブジェクトを移動させると追従するパーツ参照を作成してみます。

サンプルコード

// オブジェクトを選択
AmiPickObj PickObj;
if (amiPick(
    _T("\nパーツ参照追加するオブジェクトを選択"),
    AmiKeyType::geomKey,
    NULL,
    PickObj) != Acm::eOk) return;

AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
AcDbTransactionManager *pTransMgr = pDb->transactionManager();

try
{
    AcTransaction *pTrans = pTransMgr->startTransaction();

    AcDbFullSubentPath subentPath;
    AcGePoint3d pickPoint;
    AcGeVector3d pickVector;
    AcGeMatrix3d viewTrans;
    Adesk::Boolean isGhost;

    // 選択したときの情報を取得
    if (amiGetPickInfo(
        &PickObj,
        subentPath,
        pickPoint,
        pickVector,
        viewTrans,
        isGhost) != Acm::eOk)
    {
        pTransMgr->abortTransaction();
        return;
    }

    // パーツ参照を作成
    AcmPartRef *pPartRef = new AcmPartRef();
    pPartRef->setSymbolDefaults(pDb);
    pPartRef->setOrigin(pickPoint);

    // 現在の空間を取得
    AcDbBlockTableRecord *pCurSpace;
    pTrans->getObject((AcDbObject*&)pCurSpace, pDb->currentSpaceId(), AcDb::kForWrite);

    // パーツ参照を現在の空間に追加
    AcDbObjectId partRefId;
    if (pCurSpace->appendAcDbEntity(partRefId, pPartRef) != Acad::eOk)
    {
        delete pPartRef;
        pTransMgr->abortTransaction();
        return;
    }
    pTransMgr->addNewlyCreatedDBRObject(pPartRef);

    // ジオメトリキーを取得
    AmiGeomKey *pObjKey;
    if (amiGetGeomKey(
        Ami::geomKey, 
        Adesk::kTrue, 
        pObjKey, 
        &PickObj) != Acm::eOk)
    {
        pTransMgr->abortTransaction();
        return;
    }

    // ジオメトリ参照をアタッチする
    if (pPartRef->attachGeomRef(pObjKey, pickPoint) != Acm::eOk)
    {
        pObjKey->release();
        pTransMgr->abortTransaction();
        return;
    }

    // 現在の標準規格のObjectIdを取得
    AcDbObjectId stdId;
    if (acmStdMgr->getCurrent(stdId) != Acm::eOk)
    {
        pTransMgr->abortTransaction();
        return;
    }

    // 現在の標準規格を取得
    AcmStandard *pStandard;
    if (pTrans->getObject((AcDbObject*&)pStandard, stdId, AcDb::kForRead) != Acad::eOk)
    {
        pTransMgr->abortTransaction();
        return;
    }

    // BOMの標準規格のObjectIdを取得
    AcDbObjectId bomStdId;
    if (pStandard->getCurrentSymbolStd(L"AcmBOMStd", bomStdId) != Acad::eOk)
    {
        pTransMgr->abortTransaction();
        return;
    }

    // BOMの標準規格を取得
    AcmBOMStd *pBOMStd;
    if (pTrans->getObject((AcDbObject*&)pBOMStd, bomStdId, AcDb::kForRead) != Acad::eOk)
    {
        pTransMgr->abortTransaction();
        return;
    }

    // パーツ参照のデータ
    CMapStringToString valueMap;
    int numOfItems = 1;

    // 標準規格の列数だけループ
    for (int i = 0; i < pBOMStd->columnLength(); i++)
    {
        // 列を取得
        const AcmCColumnDef *pColumn = ((const AcmBOMStd*)pBOMStd)->column(i);
        switch (pColumn->type())
        {
        case Acm::kQuantity:
            // 数量を設定
            valueMap.SetAt(pColumn->name(), std::to_wstring(numOfItems).c_str());
            break;
        default:
            // その他の値を設定
            valueMap.SetAt(pColumn->name(), _T(""));
            break;
        }
    }

    // 部品表にパーツ参照のデータをセット
    acmBomMgr->setPartData(partRefId, numOfItems, valueMap);

    pTransMgr->endTransaction();
}
catch (...)
{
    pTransMgr->abortTransaction();
}

※サンプルコードについての補足

パーツ参照を関連付けるオブジェクトの選択には、ObjectARX 標準の acedEntSel 関数や acedSSGet 関数ではなく、amiPick 関数を使用しています。

amiPick 関数は選択したオブジェクト情報だけでなく、選択を行った入力座標などがまとめられた AmiPickObj オブジェクトが出力されます。

選択したときの情報を取得するには amiGetPickInfo 関数を使用します。サンプルコードでは amiGetPickInfo 関数で取得した入力座標を、パーツ参照の原点に設定しています。

パーツ参照を関連付けさせるには AcmPartRef クラスの attachGeomRef メソッドを使用します。 引数には AmiGeomKey オブジェクトとパーツ参照の原点座標を渡していきます。

AmiGeomKey オブジェクトは amiGetGeomKey 関数を使用して、AmiPickObj オブジェクトから取得しています。

実行結果

コマンドを実行した結果、選択したブロックに追従するパーツ参照を作成できました。

f:id:tknmt:20190313100355g:plain