Teigha for Architecture:最初のプロジェクト

AutoCAD Architecture:First project and Introduction to ACAの記事では、AutoCAD Architecture(ACA)とは何か、通常のAutoCADとの違い、実装するオブジェクトについて簡単に説明し、.NETプラグインから壁を操作する最も単純なケースを示しました。



この記事では、Teighaライブラリーについて説明します。これは、dwgファイルとACAオブジェクトを操作するための代替手段です。 ACAオブジェクトから家を作成し、dwgファイルに保存する小さな例を作成します。 次に、このファイルをAutoCAD Architectureで開き、これらのファイルが元のAutoCADと互換性があるかどうかを確認します。









AutoCADおよびObjectARXの代替



AutoCADおよびObjectARXに加えて、dwgおよびacadオブジェクトを操作するために、Open Design AllianceのTeighaという別のライブラリがあります。 dwg形式とAutoCADオブジェクトをプログラムで操作する場合、実際には、ObjectARXとTeighaの間のみを選択します。 dwgファイルを読み書きできるすべてのサードパーティコンポーネントとアプリケーションは、Teighaに基づいています。

Teighaは、通常のAutoCADとACAなどの派生物の両方のオブジェクトの読み取り、書き込み、操作を可能にするライブラリのセットです。 このライブラリには、AutoCADオブジェクトを操作するための多くの補助メカニズムと、dwgデータベースをレンダリングするためのレンダリングデバイスも実装されています。

以下は、ライブラリの機能に関するOpen Design Allianceの公式情報です。

  • サポートされているDWG、DXF、およびBDXFファイル形式:

    • バージョン2.5〜2014のファイルのサポートをお読みください。
    • バージョン12〜2014のファイルのサポートを記述します。
  • サポートされているDGNファイル形式:

    • V7およびV8 DGN(V8 XMおよびV8Iを含む)のサポートをお読みください。
    • V8 DGNのサポートを記述します。
    • V7からV8に変換します。
  • エンティティを選択できるGDI、OpenGL、またはDirectXを使用して、図面ファイルをレンダリングします。
  • 破損した.dwgファイルを回復および修復します。
  • 以下を含むプログラムでCADデータを編集および操作します。

    • エンティティをより単純なエンティティのセットに分解します。
    • エンティティに変換を適用します。
    • データベースオブジェクトの任意のプロパティを変更します。
    • データベースオブジェクトを複製します。
    • もっとたくさん。
  • SVG、PDF、DWF、BMP、STL、DAE(Collda)にエクスポートします。
  • DWF / DAE / DGNファイルを.dwgデータベースにインポートします。
  • カスタムオブジェクトのサポート-メンバーは、任意のTeighaホストアプリケーション内で使用可能なカスタムオブジェクトを作成できます(.dwgファイルとのみ互換性があります)。
  • フォントファイル(TTF / SHX)、線種ファイル(LIN / RSC)、ハッチングパターンファイル(PAT)などの外部ファイルをサポートします。
  • 寸法設定から寸法形状を再計算します。
  • .dwgファイルデータのトランザクションと元に戻す/やり直し機能をサポートします。
  • 部分的な.dwgファイルの読み込み機能をサポートし、描画エンティティの小さなサブセットへの高速アクセスを可能にします(エンティティは、クライアントから明示的にアクセスされた場合のみディスクから読み込まれます)。
  • メモリ管理をカスタマイズして、メンバーアプリケーションがメモリの割り当て/割り当て解除を制御できるようにします。
  • .dwgファイルの「往復」データをサポートします。 たとえば、2007 .dwgファイルをR14に保存し直すと、2007固有のプロパティはxdataとしてR14ファイルに保存され、ファイルが2007互換アプリケーションに再度ロードされると復元されます。
  • 埋め込まれた3Dソリッドのレンダリング(ワイヤフレームおよびシェーディング)や、基礎となる境界表現データへのアクセスなど、ACIS / Parasolidデータを内部的にサポートします。
  • カスタムコマンドを実装します。
  • サンプルソースコードアプリケーション
  • サードパーティのコンポーネントと統合します。






一般的に、「ライブラリは多くのことをサポートしています。」 まず、Teighaパッケージの標準サンプルを使用して、いくつかのdwg図面を読み込んで描画します。





OK、私たちが読んで描いたdwgファイル。 ただし、記事のタイトル画像に使用したdwgファイルのように。

この標準サンプルはウィンドウ化されたC ++アプリケーションであり、AutoCADなしでdwgファイルをダウンロード、表示、編集できます。 もう1つの重要な機能:AutoCAD APIとTeigha APIはほぼ同一であるため、既存のObjectARXプラグインをTeighaベースのアプリケーションで動作するように簡単に書き換えることができます。

BricsCAD、ZWCad、IntelliCADなど、AutoCADのほとんどのアナログは、Teighaを使用してdwg形式とacadオブジェクトを操作します。



AutoCAD Architectureオブジェクトの機能



それでは、建築オブジェクトに移り、それらを操作しましょう。 これを行うには、要点を簡単に思い出してください。

AutoCAD Architectureは、建築設計用に設計された特別な高レベルオブジェクト(壁、ドア、窓、屋根、その他の構造部品)で動作します。 ビューポート依存オブジェクト、つまり カメラの方向に応じて異なる方法でレンダリングできます。 オブジェクトにはスタイルが割り当てられます。 スタイルを変更すると、このスタイルのすべてのオブジェクトが変更されます。 オブジェクトはコンポーネントで構成され、各コンポーネントには独自の視覚設定があります:色、線の種類、素材、スケール(たとえば、3Dのドアはフレーム、キャンバス、ガラスで構成されます)。 さまざまな表示オプションの場合、オブジェクトはさまざまなジオメトリを描画するため、コンポーネントの数と設定は表現ごとに異なります。



Teigha for Architecture(TA)ライブラリ



ACA自体およびプラグインを作成するためのオープンAPIに加えて、アーキテクチャオブジェクトを操作するには、Open Design AllianceのTeigha for Architectureライブラリを使用できます。

TAはC ++クラスのライブラリで、壁、窓、ドア、屋根、梁、開口部などのすべての基本的なACAプリミティブを実装します。 ライブラリを使用すると、これらのオブジェクトをすべてのバージョンのdwg形式から読み取り、dwgの最新バージョンに書き込み(変換)できます。 ライブラリは、さまざまな表現と構成のためにすべてのプリミティブのレンダリングを実装します。 なぜなら acaオブジェクトは相互作用し、TAは補助クラスとACAメカニズムも提供します。これらはアンカー、ディスプレイマネージャー、プロパティセット、関係グラフ、その他のバインディングです。



TA APIの使用開始



私の意見では、一般的な言葉で十分です。 それでは、Teighaが物理的に何であるかを見て、最初の簡単なコマンドを書きましょう。 古いVS 2005を使用しますが、ライブラリはマルチプラットフォームであり、ソリューションには2015年までソリューション用のスタジオジェネレーターが付属しています。ライセンスの種類によっては、ライブラリ全体の完全なコード、またはビルドされたバイナリとヘッダーファイルのいずれかにアクセスできる場合があります。



TAライブラリのセットは次のようになります。





実際、これらは通常のWindows dllです(他のプラットフォーム用にビルドできます:ios、linux、unixなど)。 Libファイルは、別のフォルダーに保存されます。 TAはCoreオブジェクトの拡張であるため、TAに加えて、Teigha Coreライブラリが必要になります。 コアは、従来の自動CADの基本的なメカニズムとオブジェクトを実装します。



TAの初期化



ライブラリの初期初期化には、プラットフォーム固有のファイル操作を実行するクラスが必要です。

class MyServices : public ExSystemServices, public ExHostAppServices { protected: ODRX_USING_HEAP_OPERATORS(ExSystemServices); };
      
      





キットには、Windows用の既製の拡張機能ExSystemServicesおよびExHostAppServicesが既に含まれています。 この場合、それらは十分にあります。

次に、ライブラリとグラフィックスサブシステムを初期化します

 OdStaticRxObject<MyServices> svcs; odInitialize( &svcs ); odgsInitialize();
      
      





OdStaticRxObjectはオブジェクトロジックaddRef \ Releaseを追加します。 ライブラリはMyServicesオブジェクトへの参照を保存し、プラットフォーム固有の操作に使用します。



TAライブラリを初期化します。

  // Loading of all public Teigha Architecture DRX modules. // Note that not all calls are necessary for some of them depend on others // but here we list all of them. // // If a program uses TD doesn't modify or create binary files // it may not load any of DRX modules on start because they will be loaded automatically. // But if a program modifies or creates binary files then it is highly recommended // to load all DRX modules program uses. ::odrxDynamicLinker()->loadApp( OD_T("AecBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecArchBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecArchDACHBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecScheduleData") ); ::odrxDynamicLinker()->loadApp( OD_T("AecSchedule") ); ::odrxDynamicLinker()->loadApp( OD_T("AecStructureBase") );
      
      





AecBase、AecArchBaseおよびその他のすべては、上の図のtxモジュール(つまり、dllライブラリ)です。 それらはすでにlibファイルを使用してリンクされていますが、これでは十分ではありません。 それらをモジュールとして初期化する必要があります。 これはどういう意味ですか? 実行時には、ロードされたクラスの辞書がメモリに存在します。 このディクショナリは、異なるタイプのTAオブジェクト間でポインタをキャストするメカニズム、および疑似コンストラクタの集中メカニズムを介してTAクラス自体のインスタンスを作成するメカニズムに使用されます。

たとえば、コマンド:: odrxDynamicLinker()-> loadApp(OD_T( "AecArchBase"))を実行すると、フレームワーク内でAECArchBase :: initApp()関数が呼び出されます。 概略的に、initApp()は、それぞれに対して静的関数rxInit()を呼び出すことにより、このライブラリに実装されているクラスをグローバルディクショナリに登録します。

 … AECDbSpaceBoundary::rxInit(); AECDbStair::rxInit(); AECDbWall::rxInit(); AECDbZone::rxInit(); …
      
      





その後、オブジェクトを作成するメカニズムが機能し、たとえば、AECDbWallPtr pWall = AECDbWall :: CreateAECObject()を呼び出して壁を作成できます。 それ以外の場合、TAクラスオブジェクトを作成しようとすると、例外がスローされます。



を呼び出して空のdwgベースを作成します

 OdDbDatabasePtr pDatabase = svcs.createDatabase();
      
      





これは中心的なオブジェクトであり、dwgファイルから保存およびロードされるオブジェクトデータベースです。 作成されたすべての建築オブジェクトをそれに追加します。 完了すると、次のように呼び出して、このデータベースをdwgファイルに保存します。

 OdWrFileBuf cBuffer( strFilename ); pDatabase->writeFile( &cBuffer, OdDb::kDwg, OdDb::kDHL_CURRENT );
      
      





次に、ロードされたライブラリとディスプレイマネージャをもう少し初期化します

 AECArchDACHBaseDatabase( pDatabase ).Init(); AECScheduleDatabase( pDatabase ).Init(); AECStructureBaseDatabase( pDatabase ).Init(); init_display_system( pDatabase );
      
      





データベースにAEC辞書が作成され、長さ、面積、体積、角度、印刷設定、およびこれらのモジュールに実装されている表示表現の測定単位のデフォルト設定が登録されます。 ディスプレイマネージャー、ディスプレイ表現、および関連するメカニズムについては、別の投稿を作成します。



この初期化は完了しました。 一部のステップをスキップすると、結果が異なる場合があります。オブジェクトを作成しないか、オブジェクトが描画されない(空白の画面を参照)か、スキップしたステップに応じて、さらに不具合が発生します。



現時点では、完全なコードは次のようになっています。

プログラムコード
 class MyServices : public ExSystemServices, public ExHostAppServices { protected: ODRX_USING_HEAP_OPERATORS(ExSystemServices); }; int wmain(int argc, wchar_t* argv[]) { // Initialize TD with system services. // And create single instance of hostapp services // for TD database creation. OdStaticRxObject<MyServices> svcs; odInitialize( &svcs ); odgsInitialize(); // Loading of all public Teigha Architecture DRX modules. // Note that not all calls are necessary for some of them depend on others // but here we list all of them. // // If a program uses TD doesn't modify or create binary files // it may not load any of DRX modules on start because they will be loaded automatically. // But if a program modifies or creates binary files then it is highly recommended // to load all DRX modules program uses. ::odrxDynamicLinker()->loadApp( OD_T("AecBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecArchBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecArchDACHBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecScheduleData") ); ::odrxDynamicLinker()->loadApp( OD_T("AecSchedule") ); ::odrxDynamicLinker()->loadApp( OD_T("AecStructureBase") ); // Create empty TD database. OdDbDatabasePtr pDatabase = svcs.createDatabase();; // Initialize database with default Teigha Architecture content. AECArchDACHBaseDatabase( pDatabase ).Init(); AECScheduleDatabase( pDatabase ).Init(); AECStructureBaseDatabase( pDatabase ).Init(); init_display_system( pDatabase ); // do something here with TA objects // Perform "zoom extents" on model space. { OdDbViewportTablePtr pVT = pDatabase->getViewportTableId().openObject( OdDb::kForRead ); OdDbViewportTableRecordPtr pV = pVT->getActiveViewportId().openObject( OdDb::kForWrite ); pV->zoomExtents(); } OdWrFileBuf cBuffer( "H:\\TA_test.dwg" ); pDatabase->writeFile( &cBuffer, OdDb::kDwg, OdDb::kDHL_CURRENT ); odgsUninitialize(); odUninitialize(); return 0; }
      
      







作成したファイルを開くと、ライブラリの対称的な初期化解除を追加したオブジェクトがすぐに表示されるように、ズーム範囲コマンドを追加しました。 簡単にするために、エラーチェックを削除し、メインアクションの周りに\ catch構造を試します。

これで、プログラムは、AutoCADで開いて表示できる空のdwgファイルを作成します。



オブジェクトを操作する



図面に壁を追加する

TAクラスでの作業を示すために、地下の天井、壁、窓、ドア、屋根で構成される家を作りたいと思います。 壁から始めましょう。

まず、図面に壁を追加します。 壁自体を作成するには、最初に壁のスタイルを作成する必要があります。 add_wall_style関数を書きましょう:

Add_wall_styleコード
 OdDbObjectId add_wall_style( OdDbDatabasePtr pDatabase ) { OdDbObjectId idResult = AECDbWallStyle::CreateAECObject( pDatabase, OD_T("Wall Style Created By Teigha(R) Architecture") ); AECDbWallStylePtr pWallStyle = idResult.openObject( OdDb::kForWrite ); pWallStyle->SetDescription( OD_T("Wall Style Description") ); pWallStyle->SetDictRecordDescription( OD_T("Dialog caption") ); pWallStyle->SetWallWidth( 4 ); pWallStyle->SetWallWidthUsed( true ); pWallStyle->SetBaseHeight( 110 ); pWallStyle->SetBaseHeightUsed( true ); pWallStyle->SetJustification( AECDefs::ewjLeft ); pWallStyle->SetJustificationUsed( true ); pWallStyle->SetAutomaticCleanups( true ); pWallStyle->SetAutomaticCleanupsUsed( true ); pWallStyle->SetCleanupRadius( 4 ); pWallStyle->SetCleanupRadiusUsed( true ); pWallStyle->SetFloorLineOffset( 3 ); pWallStyle->SetFloorLineOffsetUsed( false ); pWallStyle->SetRoofLineOffset( -3 ); pWallStyle->SetRoofLineOffsetUsed( false ); AECDisplayManager cDM( pDatabase ); AECDbDispPropsWallModelPtr pOverrideModel = AECDbDispPropsWallModel::cast( pWallStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWallModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->SetIsDisplayOpeningEndcaps( false ); pOverrideModel->GetBoundaryCompByIndex( 0 )->SetColor( colorAt( 4 ) ); } AECDbDispPropsWallPtr pOverridePlan = AECDbDispPropsWall::cast( pWallStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWallPlan::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverridePlan.isNull() ) { pOverridePlan->GetBoundaryCompByIndex( 0 )->SetColor( colorAt( 4 ) ); } return( pWallStyle->objectId() ); }
      
      







この関数は、AECDbWallStyle壁スタイルオブジェクトを作成し、いくつかの設定を設定し、ディスプレイマネージャーを呼び出して、プラン表示表現(2Dトップビュー)とモデル表示表現(3Dビュー)の色を変更します。

 AECDisplayManager cDM( pDatabase ); AECDbDispPropsWallModelPtr pOverrideModel = AECDbDispPropsWallModel::cast( pWallStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWallModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->SetIsDisplayOpeningEndcaps( false ); pOverrideModel->GetBoundaryCompByIndex( 0 )->SetColor( colorAt( 2 ) ); }
      
      





この場合、3Dビューの壁に黄色を設定します。 複雑に見えますが、これには理由があります。これが、ACAのディスプレイ表現とディスプレイマネージャメカニズムの仕組みです。 柔軟性があり、多くの機能を備えていますが、そのロジックはすぐには明らかにならず、ある程度の調査が必要です。



OdDbObjectId-ランタイムリファレンス

OdDbObjectIdは、実行時にベースオブジェクトが相互に参照するクラスです。 内部では、実際のオブジェクトへのポインタをメモリに保存します。 OdDbObjectId :: openObject()を使用すると、ObjectIdが関連付けられているオブジェクトへのポインターを取得できます。 ポイントは、オブジェクトがこのIDによってアクセスされるまで、メモリにロードされず、内部ポインターOdDbObjectIdがNULLになる可能性があることです。 このIDを読み取りまたは書き込み用に具体的にオンにすると、フレームワークは実際のオブジェクトのインスタンスを作成し、そのフィールドにデータベースからのデータを入力し、内部OdDbObjectIdポインターは作成されたオブジェクトのアドレスを受け取ります。 openObject()はこのポインターを返します。

このようなメカニズムにより、大規模なデータベース(dwgファイル)の部分的な読み込みが可能になります。 この場合、各オブジェクトにはOdDbObjectIdが存在しますが、明示的にアクセスされるオブジェクトのみが実際にメモリに作成されます。

オブジェクトへのリンクを開始間で保持する場合は、OdDbHandleを使用する必要があります。



たとえば、add_wall_style関数はidWallStyleを返しました。 この場合、スタイルはAECDbWallStyle :: CreateAECObject()を呼び出して明示的に作成され、idWallStyleは内部のメモリに実際のオブジェクトへのポインターを格納します。 スタイルオブジェクトへの書き込みアクセスを取得するには、操作を実行する必要があります

 AECDbWallStylePtr pWallStyle = idResult.openObject( OdDb::kForWrite );
      
      





openObject()は、オブジェクトへの実際のポインタを返し、使用できます。



ライブラリは、通常のC ++ポインターの代わりにOdSmartPtrスマートポイントを使用します

 typedef OdSmartPtr<AECDbWallStyle> AECDbWallStylePtr
      
      





このようなスマートポイントのデストラクタは、オブジェクトのクローズをフレームワークに通知します。これにより、関連オブジェクトの再カウント、アラートの送信などが発生する可能性があります。



次を呼び出して壁を追加します。

 OdDbObjectId idWall1 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 0, 0 ), OdGePoint2d( 0, 110 ) );
      
      





Add_wallコード
 OdDbObjectId add_wall( OdDbDatabasePtr pDatabase, const OdDbObjectId& idStyle, const OdGePoint2d& ptStart, const OdGePoint2d& ptEnd, double dBulge = 0 ) { AECDbWallPtr pWall = AECDbWall::CreateAECObject( pDatabase->getModelSpaceId(), idStyle ); pWall->Set( ptStart, ptEnd, dBulge ); pWall->SetDescription( OD_T("A Wall") ); return( pWall->objectId() ); }
      
      







ご覧のとおり、add_wallは特別なことはしません。 少し前に作成したスタイルでAECDbWallオブジェクトを作成します。 AECDbWallオブジェクトは、データベースのモデル空間に追加されます。これは、データベースのレンダリング時にレンダリングされるすべてのオブジェクトを格納する特別な辞書です(これは簡略化です)。

さらに、開始点、終了点、および曲率が壁に設定されます。 つまり 壁はまっすぐであるだけでなく、凸面でもあります。



すべてが正しく行われた場合、黄色の長方形の壁が1つあるdwgファイルが取得されます。 この場合、Teighaのサンプルを使用してファイルを表示していますが、ACAでは同じ方法でレンダリングされます。



確かに、3Dビューでカメラを手動で展開しました。 デフォルトでは、上面図が表示されます。



ここで、1つの凸面で最大4つの壁を追加してみましょう。

 OdDbObjectId idWall1 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 0, 0 ), OdGePoint2d( 0, 110 ) ); OdDbObjectId idWall2 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 0, 110 ), OdGePoint2d( 110, 110 ) ); OdDbObjectId idWall3 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 110, 110 ), OdGePoint2d( 110, 0 ) ); OdDbObjectId idWall4 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 110, 0 ), OdGePoint2d( 0, 0 ), -1 );
      
      







私たちは未来の家のある種の芽を得ました:



ご覧のとおり、壁は別々のオブジェクトによって描かれているだけでなく、相互の接触点で自動的に滑らかな遷移が構築されています。 これは、クリーンアップウォールと呼ばれるTA自動機能の1つです。



現時点では完全なコード
 OdDbObjectId add_wall_style( OdDbDatabasePtr pDatabase ) { OdDbObjectId idResult = AECDbWallStyle::CreateAECObject( pDatabase, OD_T("Wall Style Created By Teigha(R) Architecture") ); AECDbWallStylePtr pWallStyle = idResult.openObject( OdDb::kForWrite ); pWallStyle->SetDescription( OD_T("Wall Style Description") ); pWallStyle->SetDictRecordDescription( OD_T("Dialog caption") ); pWallStyle->SetWallWidth( 4 ); pWallStyle->SetWallWidthUsed( true ); pWallStyle->SetBaseHeight( 110 ); pWallStyle->SetBaseHeightUsed( true ); pWallStyle->SetJustification( AECDefs::ewjLeft ); pWallStyle->SetJustificationUsed( true ); pWallStyle->SetAutomaticCleanups( true ); pWallStyle->SetAutomaticCleanupsUsed( true ); pWallStyle->SetCleanupRadius( 4 ); pWallStyle->SetCleanupRadiusUsed( true ); pWallStyle->SetFloorLineOffset( 3 ); pWallStyle->SetFloorLineOffsetUsed( false ); pWallStyle->SetRoofLineOffset( -3 ); pWallStyle->SetRoofLineOffsetUsed( false ); AECDisplayManager cDM( pDatabase ); AECDbDispPropsWallModelPtr pOverrideModel = AECDbDispPropsWallModel::cast( pWallStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWallModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->SetIsDisplayOpeningEndcaps( false ); pOverrideModel->GetBoundaryCompByIndex( 0 )->SetColor( colorAt( 4 ) ); } AECDbDispPropsWallPtr pOverridePlan = AECDbDispPropsWall::cast( pWallStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWallPlan::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverridePlan.isNull() ) { pOverridePlan->GetBoundaryCompByIndex( 0 )->SetColor( colorAt( 4 ) ); } return( pWallStyle->objectId() ); } OdDbObjectId add_wall( OdDbDatabasePtr pDatabase, const OdDbObjectId& idStyle, const OdGePoint2d& ptStart, const OdGePoint2d& ptEnd, double dBulge = 0 ) { AECDbWallPtr pWall = AECDbWall::CreateAECObject( pDatabase->getModelSpaceId(), idStyle ); pWall->Set( ptStart, ptEnd, dBulge ); pWall->SetDescription( OD_T("A Wall") ); return( pWall->objectId() ); } int wmain(int argc, wchar_t* argv[]) { // Initialize TD with system services. // And create single instance of hostapp services // for TD database creation. OdStaticRxObject<MyServices> svcs; odInitialize( &svcs ); odgsInitialize(); // Loading of all public Teigha Architecture DRX modules. // Note that not all calls are necessary for some of them depend on others // but here we list all of them. // // If a program uses TD doesn't modify or create binary files // it may not load any of DRX modules on start because they will be loaded automatically. // But if a program modifies or creates binary files then it is highly recommended // to load all DRX modules program uses. ::odrxDynamicLinker()->loadApp( OD_T("AecBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecArchBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecArchDACHBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecScheduleData") ); ::odrxDynamicLinker()->loadApp( OD_T("AecSchedule") ); ::odrxDynamicLinker()->loadApp( OD_T("AecStructureBase") ); // Create empty TD database. OdDbDatabasePtr pDatabase = svcs.createDatabase();; // Initialize database with default Teigha Architecture content. AECArchDACHBaseDatabase( pDatabase ).Init(); AECScheduleDatabase( pDatabase ).Init(); AECStructureBaseDatabase( pDatabase ).Init(); init_display_system( pDatabase ); OdDbObjectId idWallStyle = add_wall_style( pDatabase ); OdDbObjectId idWall1 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 0, 0 ), OdGePoint2d( 0, 110 ) ); OdDbObjectId idWall2 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 0, 110 ), OdGePoint2d( 110, 110 ) ); OdDbObjectId idWall3 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 110, 110 ), OdGePoint2d( 110, 0 ) ); OdDbObjectId idWall4 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 110, 0 ), OdGePoint2d( 0, 0 ), -1 ); // Perform "zoom extents" on model space. { OdDbViewportTablePtr pVT = pDatabase->getViewportTableId().openObject( OdDb::kForRead ); OdDbViewportTableRecordPtr pV = pVT->getActiveViewportId().openObject( OdDb::kForWrite ); pV->zoomExtents(); } OdWrFileBuf cBuffer( "H:\\TA_test.dwg" ); pDatabase->writeFile( &cBuffer, OdDb::kDwg, OdDb::kDHL_CURRENT ); odgsUninitialize(); odUninitialize(); return 0; }
      
      









図面へのウィンドウの追加

次に、家に窓を追加します。 ウィンドウの場合、ロジックはドアに似ています。図面に追加するウィンドウのスタイルを作成してから、このスタイルのウィンドウオブジェクトを追加する必要があります。

 OdDbObjectId idWindowStyle = add_window_style( pDatabase );
      
      





コードadd_window_style
 OdDbObjectId add_window_style( OdDbDatabasePtr pDatabase ) { OdDbObjectId idWStyle = AECDbWindowStyle::CreateAECObject( pDatabase, OD_T("Window Style Created By Teigha(R) Architecture") ); AECDbWindowStylePtr pWindowStyle = idWStyle.openObject( OdDb::kForWrite ); pWindowStyle->SetDescription( OD_T("Window Style Description") ); pWindowStyle->SetDictRecordDescription( OD_T("Dialog caption") ); pWindowStyle->SetAutoAdjustToWidthOfWall( true ); pWindowStyle->SetFrameWidth( 2 ); pWindowStyle->SetFrameDepth( 5 ); pWindowStyle->SetSashWidth( 2 ); pWindowStyle->SetSashDepth( 3 ); pWindowStyle->SetGlassThickness( 1 ); pWindowStyle->SetWindowType( AECDefs::ewtGlider ); pWindowStyle->SetWindowShape( AECDefs::esRectangular ); AECDisplayManager cDM( pDatabase ); AECDbDispPropsWindowPtr pOverrideModel = AECDbDispPropsWindow::cast( pWindowStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWindowModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->GetFrameComp()->SetColor( colorAt( 1 ) ); pOverrideModel->GetSashComp()->SetColor( colorAt( 2 ) ); pOverrideModel->GetGlassComp()->SetColor( colorAt( 3 ) ); } AECDbDispPropsWindowPtr pOverridePlan = AECDbDispPropsWindow::cast( pWindowStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWindowPlan::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverridePlan.isNull() ) { pOverridePlan->GetFrameComp()->SetColor( colorAt( 1 ) ); pOverridePlan->GetSashComp()->SetColor( colorAt( 2 ) ); pOverridePlan->GetGlassComp()->SetColor( colorAt( 3 ) ); } return( pWindowStyle->objectId() ); }
      
      







コードからわかるように、AECDbWindowStyleオブジェクトが作成され、データベースに追加されます。 次に、スタイルをいくつかの設定に設定し(デフォルトの設定を使用できます)、2Dおよび3D表現用にいくつかのコンポーネントの色を再定義します。 この場合のコンポーネントは、ガラス、フレーム、サッシなど、ウィンドウの物理的な部分です。



add_window関数を使用して、最初の壁にウィンドウを追加します。

 OdDbObjectId idWindow01 = add_window( pDatabase, idWindowStyle, idWall1, 10, 10 );
      
      





add_window関数コード
 // Inserts a window into a database using the specified window style. // If idWall parameter is not null it also attaches the window to the wall. // Returns Object ID of newly created window. OdDbObjectId add_window( OdDbDatabasePtr pDatabase, const OdDbObjectId& idStyle, const OdDbObjectId& idWall, double dOffsetAlongX, double dOffsetAlongZ ) { AECDbWindowPtr pWindow = AECDbWindow::CreateAECObject( pDatabase->getModelSpaceId(), idStyle ); pWindow->SetRise( 10 ); pWindow->SetWidth( 40 ); pWindow->SetHeight( 40 ); pWindow->SetOpenPercent( 60 ); pWindow->SetMeasureTo( AECDefs::eomtOutsideFrame ); pWindow->SetLeaf( 10 ); if ( !idWall.isNull() ) { pWindow->AttachWallAnchor( idWall ); AECDbAnchorEntToCurvePtr pAnchor = pWindow->GetAnchor().openObject( OdDb::kForWrite ); pAnchor->GetXParams()->SetOffset( dOffsetAlongX ); pAnchor->GetZParams()->SetOffset( dOffsetAlongZ ); } return( pWindow->objectId() ); }
      
      







add_window()関数はadd_wall()と似ていますが、1つの違いがあります。ここではアンカーオブジェクトが使用されます。

AECDbWindowオブジェクトを作成し、ベースのモデル空間に配置します。 次に、AECDbWindowのこの特定のインスタンスにいくつかの設定を公開します。

その後、窓を壁に挿入します。 壁と窓は、AECDbAnchorEntToCurveから派生した特別なオブジェクトによって接続されています。 壁の座標系の始点からウィンドウの座標系の始点までのx、y、z軸に沿ったインデントが含まれます。 AttachWallAnchor()を呼び出すと、このオブジェクトのインスタンスが作成され、データベースに配置されます。 壁自体は、窓が壁に挿入されているかどうかを直接知りません。 アンカーの作成は、別の基本的なメカニズムであるリレーショングラフに影響します。 関係グラフには、オブジェクト間の関係が含まれています-誰が誰に、誰が誰に、誰が誰を所有しているか。 壁を変更すると、リレーショングラフはAECDbWallオブジェクトが変更され、すべての依存関係を通過し、関連オブジェクト(この場合はAECDbWindow)を更新するというメッセージを受け取ります。 したがって、壁を移動すると、リレーショングラフから通知を受け取るため、ウィンドウはそれに沿って移動します。 このグラフにアクセスして、特定のオブジェクトの依存関係を要求できます。 ウィンドウは、作成されたアンカーへのリンクを保存するため、原則として、誰にアタッチされているかを認識しています。



何が起こったのか見てみましょう:





窓が見やすくなるように、壁の色を具体的に変更しました。 コードでは、壁はすぐに青色になるはずです。記事を書いたときに色を選択しました。

TAには、列挙によって指定された多くの定義済みのスタイルとウィンドウのタイプがあります。

 enum WindowType { ewtPicture = 1, ewtSingleHung = 2, ewtDoubleHung = 3, ewtAwningTransom = 4, ewtDoubleCasement = 5, ewtGlider = 6, ewtHopperTransom = 7, ewtPassThrough = 8, ewtSingleCasement = 9, ewtSingleHopper = 10, ewtSingleAwning = 11, ewtVerticalPivot = 12, ewtHorizontalPivot = 13, ewtUnevenSingleHung = 14, ewtUnevenDoubleHung = 15 }; enum Shape { esRectangular = 0, esRound = 1, esHalfRound = 2, esQuarterRound = 3, esOval = 4, esArch = 5, esTrapezoid = 6, esGothic = 7, esIsoscelesTriangle = 8, esRightTriangle = 9, esPeakPentagon = 10, esOctagon = 11, esHexagon = 12, esCustom = 13 };
      
      





AECDefs :: ewtGliderおよびAECDefs :: esRectangularを選択しましたが、ご覧のとおり、形状には多くのオプションがあります。 他の設定を使用すると、ガラスの内部パターンと多くのサッシで非常に複雑なタイプのウィンドウを作成できます。 そして、これらすべてを手動で描画したり、プログラムで実装したりする必要はありません。既存のオブジェクトまたはスタイルの設定をいくつか設定するだけで済みます。

一般に、すべてのTAオブジェクトは複雑で、多数の設定があります。 これにより、箱から出してすぐに非常に多くの機会が与えられます。



すべてのまっすぐな壁に窓を追加します。

 OdDbObjectId idWindow01 = add_window( pDatabase, idWindowStyle, idWall1, 10, 10 ); OdDbObjectId idWindow02 = add_window( pDatabase, idWindowStyle, idWall1, 60, 10 ); OdDbObjectId idWindow03 = add_window( pDatabase, idWindowStyle, idWall1, 10, 60 ); OdDbObjectId idWindow04 = add_window( pDatabase, idWindowStyle, idWall1, 60, 60 ); OdDbObjectId idWindow05 = add_window( pDatabase, idWindowStyle, idWall2, 10, 10 ); OdDbObjectId idWindow06 = add_window( pDatabase, idWindowStyle, idWall2, 60, 10 ); OdDbObjectId idWindow07 = add_window( pDatabase, idWindowStyle, idWall2, 10, 60 ); OdDbObjectId idWindow08 = add_window( pDatabase, idWindowStyle, idWall2, 60, 60 ); OdDbObjectId idWindow09 = add_window( pDatabase, idWindowStyle, idWall3, 10, 10 ); OdDbObjectId idWindow10 = add_window( pDatabase, idWindowStyle, idWall3, 60, 10 ); OdDbObjectId idWindow11 = add_window( pDatabase, idWindowStyle, idWall3, 10, 60 ); OdDbObjectId idWindow12 = add_window( pDatabase, idWindowStyle, idWall3, 60, 60 );
      
      









コードの追加は開始しませんでしたが、各ウィンドウは個別に制御できます。開口部の割合、色などを変更します。 そして、スタイルを変更すると、この変更はすべてのユーザーに同時に影響します。



図面にドアを追加する

写真を完成させるには、ドアを追加します。 ドアについては、キャンバス(穴窓のあるリーフ)の2Dプロファイルを作成し、そのようなプロファイルを使用してスタイルを作成します。次に、このスタイルのドアオブジェクトを作成できます。 ただし、デフォルトのスタイルを使用できます。 窓のようなドア(および他のすべての開口部)は、アンカーを使用して壁に結合されます。

コードadd_profile_def、add_door_style、add_door
 // Inserts profile definition into a database. // Returns Object ID of newly created profile definition. OdDbObjectId add_profile_def( OdDbDatabasePtr pDatabase ) { OdDbObjectId idProfDef = AECDbProfileDef::CreateAECObject( pDatabase, OD_T("Profile Definition Created By Teigha(R) Architecture") ); AECDbProfileDefPtr pProfileDefinition = idProfDef.openObject( OdDb::kForWrite ); AECGe::Profile2D cProfile; cProfile.resize( 2 ); cProfile[ 0 ].appendVertex( OdGePoint2d( 0, 0 ) ); cProfile[ 0 ].appendVertex( OdGePoint2d( 1, 0 ) ); cProfile[ 0 ].appendVertex( OdGePoint2d( 1, 1 ) ); cProfile[ 0 ].appendVertex( OdGePoint2d( 0, 1 ) ); cProfile[ 0 ].setClosed(); // Forces the contour to be counter-clockwise. // So if the contour is already ccw this call is not needed. cProfile[ 0 ].makeCCW(); cProfile[ 1 ].appendVertex( OdGePoint2d( 0.2, 0.2 ) ); cProfile[ 1 ].appendVertex( OdGePoint2d( 0.2, 0.8 ) ); cProfile[ 1 ].appendVertex( OdGePoint2d( 0.8, 0.8 ) ); cProfile[ 1 ].appendVertex( OdGePoint2d( 0.8, 0.2 ) ); cProfile[ 1 ].setClosed(); cProfile[ 1 ].makeCCW( false ); pProfileDefinition->GetProfile()->Init( cProfile ); return( pProfileDefinition->objectId() ); } // Inserts a door style into a database. // Returns Object ID of newly created door style. OdDbObjectId add_door_style( OdDbDatabasePtr pDatabase, const OdDbObjectId& idProfile ) { OdDbObjectId idDoorStyle = AECDbDoorStyle::CreateAECObject( pDatabase, OD_T("Door Style Created By Teigha(R) Architecture") ); AECDbDoorStylePtr pDoorStyle = idDoorStyle.openObject( OdDb::kForWrite ); pDoorStyle->SetDescription( OD_T("Door Style Description") ); pDoorStyle->SetDictRecordDescription( OD_T("Dialog caption") ); pDoorStyle->SetAutoAdjustToWidthOfWall( true ); pDoorStyle->SetFrameWidth( 2 ); pDoorStyle->SetFrameDepth( 5 ); pDoorStyle->SetStopWidth( 2 ); pDoorStyle->SetStopDepth( 3 ); pDoorStyle->SetShapeAndType( AECDefs::esCustom, AECDefs::edtSingle ); pDoorStyle->SetProfile( idProfile ); pDoorStyle->SetGlassThickness( 1 ); AECDisplayManager cDM( pDatabase ); AECDbDispPropsDoorPtr pOverrideModel = AECDbDispPropsDoor::cast( pDoorStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepDoorModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->GetPanelComp()->SetColor( colorAt( 1 ) ); pOverrideModel->GetFrameComp()->SetColor( colorAt( 2 ) ); pOverrideModel->GetStopComp()->SetColor( colorAt( 3 ) ); pOverrideModel->GetSwingComp()->SetColor( colorAt( 4 ) ); pOverrideModel->GetGlassComp()->SetColor( colorAt( 5 ) ); } AECDbDispPropsDoorPtr pOverridePlan = AECDbDispPropsDoor::cast( pDoorStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepDoorPlan::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverridePlan.isNull() ) { pOverridePlan->GetPanelComp()->SetColor( colorAt( 1 ) ); pOverridePlan->GetFrameComp()->SetColor( colorAt( 2 ) ); pOverridePlan->GetStopComp()->SetColor( colorAt( 3 ) ); pOverridePlan->GetSwingComp()->SetColor( colorAt( 4 ) ); pOverridePlan->GetDirectionComp()->SetColor( colorAt( 5 ) ); } return( pDoorStyle->objectId() ); } // Inserts a door into a database using the specified door style. // If idWall parameter is not null it also attaches the door to the wall. // Returns Object ID of newly created door. OdDbObjectId add_door( OdDbDatabasePtr pDatabase, const OdDbObjectId& idStyle, const OdDbObjectId& idWall, double dOffsetAlongX, double dOffsetAlongZ ) { AECDbDoorPtr pDoor = AECDbDoor::CreateAECObject( pDatabase->getModelSpaceId(), idStyle ); pDoor->SetRise( 10 ); pDoor->SetWidth( 40 ); pDoor->SetHeight( 50 ); pDoor->SetOpenPercent( 20 ); pDoor->SetMeasureTo( AECDefs::eomtOutsideFrame ); pDoor->SetLeaf( 10 ); if ( !idWall.isNull() ) { pDoor->AttachWallAnchor( idWall ); AECDbAnchorEntToCurvePtr pAnchor = pDoor->GetAnchor().openObject( OdDb::kForWrite ); pAnchor->GetXParams()->SetOffset( dOffsetAlongX ); pAnchor->GetZParams()->SetOffset( dOffsetAlongZ ); } return( pDoor->objectId() ); }
      
      







メインに追加します:

 AECDbWallPtr pWall = idWall4.openObject( OdDb::kForRead ); double dLength = pWall->GetLength(); double dOWidth = 40; double dL1 = 10; double dL3 = dLength - dOWidth - 10; double dL2 = dL1 + dOWidth + (dL3 - (dL1 + 2 * dOWidth)) / 2; OdDbObjectId idDoor = add_door ( pDatabase, idDoorStyle, idWall4, dL2, 0 );
      
      





ここに1つの新しいポイントがあります。読み取り用に壁を開き、その長さを使用してインデントを計算します。



その結果、ドアが丸い壁に挿入されました。丸い壁に





別のウィンドウを挿入します。

 OdDbObjectId idWindow13 = add_window ( pDatabase, idWindowStyle, idWall4, dL1, 10 ); OdDbObjectId idWindow14 = add_window ( pDatabase, idWindowStyle, idWall4, dL3, 10 ); OdDbObjectId idWindow15 = add_window ( pDatabase, idWindowStyle, idWall4, dL1, 60 ); OdDbObjectId idWindow16 = add_window ( pDatabase, idWindowStyle, idWall4, dL2, 60 ); OdDbObjectId idOpening = add_window ( pDatabase, idWindowStyle, idWall4, dL3, 60 );
      
      







その結果、屋根と床のない非常に穴の開いた家ができました:





図面に屋根を追加する

add_roof()関数を書きましょう

ルーフ機能コード
 void add_roof( OdDbDatabasePtr pDatabase ) { AECGe::Profile2D cProfile; cProfile.resize( 1 ); cProfile.front().appendVertex( OdGePoint2d( 0, 0 ) ); cProfile.front().appendVertex( OdGePoint2d( 0, 110 ) ); cProfile.front().appendVertex( OdGePoint2d( 110, 110 ) ); cProfile.front().appendVertex( OdGePoint2d( 110, 0 ), -1 ); cProfile.front().setClosed(); cProfile.front().makeCCW(); AECDbRoofPtr pRoof = AECDbRoof::CreateAECObject( pDatabase->getModelSpaceId() ); // Initialize roof profile. // By default all edges of Roof Profile have single slope of 45 degrees. pRoof->GetProfile()->Init( cProfile ); pRoof->SetThickness( 2 ); //// Manually modify Roof Segments. AECGeRingSubPtr pRoofLoop = pRoof->GetProfile()->GetRingByIndex( 0 ); if ( !pRoofLoop.isNull() ) { OdUInt32 i, iSize = pRoofLoop->GetSegmentCount(); for ( i = 0; i < iSize; i++ ) { AECGeRoofSegmentSubPtr pSeg = pRoofLoop->GetSegments()->GetAt( i ); pSeg->SetFaceCount(1); pSeg->SetFaceHeightByIndex(0, 110); pSeg->SetBaseHeight(0); pSeg->SetOverhang(10.0); pSeg->SetFaceSlopeByIndex(0, OdaPI4); pSeg->SetSegmentCount(10); } } pRoof->setColorIndex( 3 ); }
      
      







屋根は、バイパス方向が反時計回りである2次元プロファイルに基づいて作成されます。 makeCCW()の呼び出しは、バイパス方向が逆の場合にのみ変換します。これは重要です。なぜなら、アルゴリズムはそのようなプロファイルを入力することを期待しており、それ以外の場合は機能しないからです。

私たちのプロファイルは、壁の中心線と一致しています。さらに、プロファイルの各セクションについて、屋根の勾配の勾配、勾配が提示される面の数、OXY平面に対するZから始まる勾配の上昇(SetFaceHeightByIndex)、および屋根の張り出し(オーバーハング)が設定されます。 SetSegmentCount()は、曲率を持つセグメントでのみ機能します。この値は、近似精度(半円形セグメントを近似するために使用される直線セグメントの数)を設定します。



そのような屋根が判明しました:





屋根の設定には多くのバリエーションがあり、切妻、マルチスロープ、テントなど、ほぼすべての形状の屋根を作成できます。各スロープは個別のRoofSlabオブジェクトであり、手動で編集できます。



図面にオーバーラップを追加する

床/基礎の少なくとも小さな模倣を追加することは残っています。これを行うには、スラブオブジェクトを使用します(オーバーラップ)。add_slab関数を書きましょう

add_slab関数コード
 void add_slab( OdDbDatabasePtr pDatabase ) { OdDbObjectId idStyle = AECDbSlabStyle::GetAECObject( pDatabase, OD_T("Slab Style") ); if ( idStyle.isNull() ) { idStyle = AECDbSlabStyle::CreateAECObject( pDatabase, OD_T("Slab Style") ); } AECDbSlabStylePtr pStyle = idStyle.openObject( OdDb::kForWrite ); if ( !pStyle.isNull() ) { pStyle->GetComponents()->Clear(); AECSlabStyleCompPtr pCmp = AECSlabStyleComp::createObject(); pCmp->SetName( OD_T("Base") ); pCmp->GetPosition()->GetThickness()->SetUseBaseValue( false ); pCmp->GetPosition()->GetThickness()->SetBaseValue( 6 ); pCmp->GetPosition()->GetThicknessOffset()->SetUseBaseValue( false ); pCmp->GetPosition()->GetThicknessOffset()->SetBaseValue( - 6 ); pStyle->GetComponents()->Insert( pCmp ); } AECDbSlabPtr pSlab = AECDbSlab::CreateAECObject( pDatabase->getModelSpaceId(), idStyle ); { AECGe::Profile2D cBase; cBase.resize( 1 ); cBase.front().appendVertex( OdGePoint2d( -5, -5 ), 1 ); cBase.front().appendVertex( OdGePoint2d( 115, -5 ) ); cBase.front().appendVertex( OdGePoint2d( 115, 115 ) ); cBase.front().appendVertex( OdGePoint2d( -5, 115 ) ); cBase.front().setClosed(); cBase.front().makeCCW(); pSlab->GetSlabFace()->Init( cBase ); } pSlab->SetThickness( 5 ); pSlab->SetVerticalOffset( 0 ); pSlab->SetHorizontalOffset( 0 ); pSlab->SetPivotPoint( OdGePoint3d::kOrigin ); AECDisplayManager cDM( pDatabase ); AECDbDispPropsSlabPtr pOverrideModel = AECDbDispPropsSlab::cast( pSlab->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepSlabModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->GetBoundaryCompByIndex( 0 )->SetColor( colorAt( 1 ) ); pOverrideModel->GetBaselineComp()->SetColor( colorAt( 4 ) ); pOverrideModel->GetPivotPointComp()->SetColor( colorAt( 5 ) ); pOverrideModel->GetFasciaComp()->SetColor( colorAt( 6 ) ); pOverrideModel->GetSoffitComp()->SetColor( colorAt( 7 ) ); pOverrideModel->GetShrinkWrapBodyComp()->SetColor( colorAt( 8 ) ); } AECDbDispPropsSlabPlanPtr pOverridePlan = AECDbDispPropsSlabPlan::cast( pSlab->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepSlabPlan::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverridePlan.isNull() ) { pOverridePlan->SetIsOverrideCutPlane( false ); pOverridePlan->GetHatchComp()->SetColor( colorAt( 1 ) ); pOverridePlan->GetBelowCutPlaneBodyComp()->SetColor( colorAt( 2 ) ); pOverridePlan->GetAboveCutPlaneBodyComp()->SetColor( colorAt( 3 ) ); pOverridePlan->GetBelowCutPlaneOutlineComp()->SetColor( colorAt( 4 ) ); pOverridePlan->GetAboveCutPlaneOutlineComp()->SetColor( colorAt( 5 ) ); } }
      
      







この場合、新しいオーバーラップスタイルを作成し、それにコンポーネントを追加します。コンポーネントはオーバーラップの一部で、厚さ、OXYを超える上昇、名前、素材、インデックスなどのパラメーターが含まれます。オーバーラップは、設定が異なる複数のコンポーネントを含むことができます。たとえば、OXYとは異なるマージンがある場合、このスタイルの1つのオブジェクトオーバーラップは、高層ビルのすべての床と天井を描画できます。

スタイル設定は、このオーバーラップの形状を保存する特定のオブジェクトに適用されます。この場合、スラブを作成し、そのプロファイルを壁の底と同じ輪郭で初期化します。エッジに沿ってわずかにくぼみを付けます。

次のステップでは、ディスプレイマネージャと連携して、異なるオーバーラップコンポーネントの色をオーバーライドします。



最終的に、私たちの家は次のようになります。





テストのために、生成されたdwgファイルをAutodesk ACAにアップロードしてみましょう。AutocadArchitecture



にアップロードされた私たちの家です。それはさらに良く見えます。



完全なコード
 OdDbObjectId add_wall_style( OdDbDatabasePtr pDatabase ) { OdDbObjectId idResult = AECDbWallStyle::CreateAECObject( pDatabase, OD_T("Wall Style Created By Teigha(R) Architecture") ); AECDbWallStylePtr pWallStyle = idResult.openObject( OdDb::kForWrite ); pWallStyle->SetDescription( OD_T("Wall Style Description") ); pWallStyle->SetDictRecordDescription( OD_T("Dialog caption") ); pWallStyle->SetWallWidth( 4 ); pWallStyle->SetWallWidthUsed( true ); pWallStyle->SetBaseHeight( 110 ); pWallStyle->SetBaseHeightUsed( true ); pWallStyle->SetJustification( AECDefs::ewjLeft ); pWallStyle->SetJustificationUsed( true ); pWallStyle->SetAutomaticCleanups( true ); pWallStyle->SetAutomaticCleanupsUsed( true ); pWallStyle->SetCleanupRadius( 4 ); pWallStyle->SetCleanupRadiusUsed( true ); pWallStyle->SetFloorLineOffset( 3 ); pWallStyle->SetFloorLineOffsetUsed( false ); pWallStyle->SetRoofLineOffset( -3 ); pWallStyle->SetRoofLineOffsetUsed( false ); AECDisplayManager cDM( pDatabase ); AECDbDispPropsWallModelPtr pOverrideModel = AECDbDispPropsWallModel::cast( pWallStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWallModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->SetIsDisplayOpeningEndcaps( false ); pOverrideModel->GetBoundaryCompByIndex( 0 )->SetColor( colorAt( 4 ) ); } AECDbDispPropsWallPtr pOverridePlan = AECDbDispPropsWall::cast( pWallStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWallPlan::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverridePlan.isNull() ) { pOverridePlan->GetBoundaryCompByIndex( 0 )->SetColor( colorAt( 4 ) ); } return( pWallStyle->objectId() ); } OdDbObjectId add_wall( OdDbDatabasePtr pDatabase, const OdDbObjectId& idStyle, const OdGePoint2d& ptStart, const OdGePoint2d& ptEnd, double dBulge = 0 ) { AECDbWallPtr pWall = AECDbWall::CreateAECObject( pDatabase->getModelSpaceId(), idStyle ); pWall->Set( ptStart, ptEnd, dBulge ); pWall->SetDescription( OD_T("A Wall") ); /*AECGe::Contour2D cContour; cContour.appendVertex( OdGePoint2d( 0, pWall->GetHeight() ) ); cContour.appendVertex( OdGePoint2d( pWall->GetLength() / 2, pWall->GetHeight() * 1.5 ) ); cContour.appendVertex( OdGePoint2d( pWall->GetLength(), pWall->GetHeight() ) ); AECWallCutLineSubPtr pTop = pWall->CreateTopCutLine(); pTop->SetRawCutLine( cContour );*/ return( pWall->objectId() ); } OdDbObjectId add_window_style( OdDbDatabasePtr pDatabase ) { OdDbObjectId idWStyle = AECDbWindowStyle::CreateAECObject( pDatabase, OD_T("Window Style Created By Teigha(R) Architecture") ); AECDbWindowStylePtr pWindowStyle = idWStyle.openObject( OdDb::kForWrite ); pWindowStyle->SetDescription( OD_T("Window Style Description") ); pWindowStyle->SetDictRecordDescription( OD_T("Dialog caption") ); pWindowStyle->SetAutoAdjustToWidthOfWall( true ); pWindowStyle->SetFrameWidth( 2 ); pWindowStyle->SetFrameDepth( 5 ); pWindowStyle->SetSashWidth( 2 ); pWindowStyle->SetSashDepth( 3 ); pWindowStyle->SetGlassThickness( 1 ); pWindowStyle->SetWindowType( AECDefs::ewtGlider ); pWindowStyle->SetWindowShape( AECDefs::esRectangular ); AECDisplayManager cDM( pDatabase ); AECDbDispPropsWindowPtr pOverrideModel = AECDbDispPropsWindow::cast( pWindowStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWindowModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->GetFrameComp()->SetColor( colorAt( 1 ) ); pOverrideModel->GetSashComp()->SetColor( colorAt( 2 ) ); pOverrideModel->GetGlassComp()->SetColor( colorAt( 3 ) ); } AECDbDispPropsWindowPtr pOverridePlan = AECDbDispPropsWindow::cast( pWindowStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepWindowPlan::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverridePlan.isNull() ) { pOverridePlan->GetFrameComp()->SetColor( colorAt( 1 ) ); pOverridePlan->GetSashComp()->SetColor( colorAt( 2 ) ); pOverridePlan->GetGlassComp()->SetColor( colorAt( 3 ) ); } return( pWindowStyle->objectId() ); } // Inserts a window into a database using the specified window style. // If idWall parameter is not null it also attaches the window to the wall. // Returns Object ID of newly created window. OdDbObjectId add_window( OdDbDatabasePtr pDatabase, const OdDbObjectId& idStyle, const OdDbObjectId& idWall, double dOffsetAlongX, double dOffsetAlongZ ) { AECDbWindowPtr pWindow = AECDbWindow::CreateAECObject( pDatabase->getModelSpaceId(), idStyle ); pWindow->SetRise( 10 ); pWindow->SetWidth( 40 ); pWindow->SetHeight( 40 ); pWindow->SetOpenPercent( 60 ); pWindow->SetMeasureTo( AECDefs::eomtOutsideFrame ); pWindow->SetLeaf( 10 ); if ( !idWall.isNull() ) { pWindow->AttachWallAnchor( idWall ); AECDbAnchorEntToCurvePtr pAnchor = pWindow->GetAnchor().openObject( OdDb::kForWrite ); pAnchor->GetXParams()->SetOffset( dOffsetAlongX ); pAnchor->GetZParams()->SetOffset( dOffsetAlongZ ); } return( pWindow->objectId() ); } // Inserts profile definition into a database. // Returns Object ID of newly created profile definition. OdDbObjectId add_profile_def( OdDbDatabasePtr pDatabase ) { OdDbObjectId idProfDef = AECDbProfileDef::CreateAECObject( pDatabase, OD_T("Profile Definition Created By Teigha(R) Architecture") ); AECDbProfileDefPtr pProfileDefinition = idProfDef.openObject( OdDb::kForWrite ); AECGe::Profile2D cProfile; cProfile.resize( 2 ); cProfile[ 0 ].appendVertex( OdGePoint2d( 0, 0 ) ); cProfile[ 0 ].appendVertex( OdGePoint2d( 1, 0 ) ); cProfile[ 0 ].appendVertex( OdGePoint2d( 1, 1 ) ); cProfile[ 0 ].appendVertex( OdGePoint2d( 0, 1 ) ); cProfile[ 0 ].setClosed(); // Forces the contour to be counter-clockwise. // So if the contour is already ccw this call is not needed. cProfile[ 0 ].makeCCW(); cProfile[ 1 ].appendVertex( OdGePoint2d( 0.2, 0.2 ) ); cProfile[ 1 ].appendVertex( OdGePoint2d( 0.2, 0.8 ) ); cProfile[ 1 ].appendVertex( OdGePoint2d( 0.8, 0.8 ) ); cProfile[ 1 ].appendVertex( OdGePoint2d( 0.8, 0.2 ) ); cProfile[ 1 ].setClosed(); cProfile[ 1 ].makeCCW( false ); pProfileDefinition->GetProfile()->Init( cProfile ); return( pProfileDefinition->objectId() ); } // Inserts a door style into a database. // Returns Object ID of newly created door style. OdDbObjectId add_door_style( OdDbDatabasePtr pDatabase, const OdDbObjectId& idProfile ) { OdDbObjectId idDoorStyle = AECDbDoorStyle::CreateAECObject( pDatabase, OD_T("Door Style Created By Teigha(R) Architecture") ); AECDbDoorStylePtr pDoorStyle = idDoorStyle.openObject( OdDb::kForWrite ); pDoorStyle->SetDescription( OD_T("Door Style Description") ); pDoorStyle->SetDictRecordDescription( OD_T("Dialog caption") ); pDoorStyle->SetAutoAdjustToWidthOfWall( true ); pDoorStyle->SetFrameWidth( 2 ); pDoorStyle->SetFrameDepth( 5 ); pDoorStyle->SetStopWidth( 2 ); pDoorStyle->SetStopDepth( 3 ); pDoorStyle->SetShapeAndType( AECDefs::esCustom, AECDefs::edtSingle ); pDoorStyle->SetProfile( idProfile ); pDoorStyle->SetGlassThickness( 1 ); AECDisplayManager cDM( pDatabase ); AECDbDispPropsDoorPtr pOverrideModel = AECDbDispPropsDoor::cast( pDoorStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepDoorModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->GetPanelComp()->SetColor( colorAt( 1 ) ); pOverrideModel->GetFrameComp()->SetColor( colorAt( 2 ) ); pOverrideModel->GetStopComp()->SetColor( colorAt( 3 ) ); pOverrideModel->GetSwingComp()->SetColor( colorAt( 4 ) ); pOverrideModel->GetGlassComp()->SetColor( colorAt( 5 ) ); } AECDbDispPropsDoorPtr pOverridePlan = AECDbDispPropsDoor::cast( pDoorStyle->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepDoorPlan::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverridePlan.isNull() ) { pOverridePlan->GetPanelComp()->SetColor( colorAt( 1 ) ); pOverridePlan->GetFrameComp()->SetColor( colorAt( 2 ) ); pOverridePlan->GetStopComp()->SetColor( colorAt( 3 ) ); pOverridePlan->GetSwingComp()->SetColor( colorAt( 4 ) ); pOverridePlan->GetDirectionComp()->SetColor( colorAt( 5 ) ); } return( pDoorStyle->objectId() ); } // Inserts a door into a database using the specified door style. // If idWall parameter is not null it also attaches the door to the wall. // Returns Object ID of newly created door. OdDbObjectId add_door( OdDbDatabasePtr pDatabase, const OdDbObjectId& idStyle, const OdDbObjectId& idWall, double dOffsetAlongX, double dOffsetAlongZ ) { AECDbDoorPtr pDoor = AECDbDoor::CreateAECObject( pDatabase->getModelSpaceId(), idStyle ); pDoor->SetRise( 10 ); pDoor->SetWidth( 40 ); pDoor->SetHeight( 50 ); pDoor->SetOpenPercent( 20 ); pDoor->SetMeasureTo( AECDefs::eomtOutsideFrame ); pDoor->SetLeaf( 10 ); if ( !idWall.isNull() ) { pDoor->AttachWallAnchor( idWall ); AECDbAnchorEntToCurvePtr pAnchor = pDoor->GetAnchor().openObject( OdDb::kForWrite ); pAnchor->GetXParams()->SetOffset( dOffsetAlongX ); pAnchor->GetZParams()->SetOffset( dOffsetAlongZ ); } return( pDoor->objectId() ); } void add_roof( OdDbDatabasePtr pDatabase ) { AECGe::Profile2D cProfile; cProfile.resize( 1 ); cProfile.front().appendVertex( OdGePoint2d( 0, 0 ) ); cProfile.front().appendVertex( OdGePoint2d( 0, 110 ) ); cProfile.front().appendVertex( OdGePoint2d( 110, 110 ) ); cProfile.front().appendVertex( OdGePoint2d( 110, 0 ), -1 ); cProfile.front().setClosed(); cProfile.front().makeCCW(); AECDbRoofPtr pRoof = AECDbRoof::CreateAECObject( pDatabase->getModelSpaceId() ); // Initialize roof profile. // By default all edges of Roof Profile have single slope of 45 degrees. pRoof->GetProfile()->Init( cProfile ); pRoof->SetThickness( 2 ); //// Manually modify Roof Segments. AECGeRingSubPtr pRoofLoop = pRoof->GetProfile()->GetRingByIndex( 0 ); if ( !pRoofLoop.isNull() ) { OdUInt32 i, iSize = pRoofLoop->GetSegmentCount(); for ( i = 0; i < iSize; i++ ) { AECGeRoofSegmentSubPtr pSeg = pRoofLoop->GetSegments()->GetAt( i ); pSeg->SetFaceCount(1); pSeg->SetFaceHeightByIndex(0, 110); pSeg->SetBaseHeight(0); pSeg->SetOverhang(10.0); pSeg->SetFaceSlopeByIndex(0, OdaPI4); pSeg->SetSegmentCount(10); } } pRoof->setColorIndex( 3 ); } void add_slab( OdDbDatabasePtr pDatabase ) { OdDbObjectId idStyle = AECDbSlabStyle::GetAECObject( pDatabase, OD_T("Slab Style") ); if ( idStyle.isNull() ) { idStyle = AECDbSlabStyle::CreateAECObject( pDatabase, OD_T("Slab Style") ); } AECDbSlabStylePtr pStyle = idStyle.openObject( OdDb::kForWrite ); if ( !pStyle.isNull() ) { pStyle->GetComponents()->Clear(); AECSlabStyleCompPtr pCmp = AECSlabStyleComp::createObject(); pCmp->SetName( OD_T("Base") ); pCmp->GetPosition()->GetThickness()->SetUseBaseValue( false ); pCmp->GetPosition()->GetThickness()->SetBaseValue( 6 ); pCmp->GetPosition()->GetThicknessOffset()->SetUseBaseValue( false ); pCmp->GetPosition()->GetThicknessOffset()->SetBaseValue( - 6 ); pStyle->GetComponents()->Insert( pCmp ); } AECDbSlabPtr pSlab = AECDbSlab::CreateAECObject( pDatabase->getModelSpaceId(), idStyle ); { AECGe::Profile2D cBase; cBase.resize( 1 ); cBase.front().appendVertex( OdGePoint2d( -5, -5 ), 1 ); cBase.front().appendVertex( OdGePoint2d( 115, -5 ) ); cBase.front().appendVertex( OdGePoint2d( 115, 115 ) ); cBase.front().appendVertex( OdGePoint2d( -5, 115 ) ); cBase.front().setClosed(); cBase.front().makeCCW(); pSlab->GetSlabFace()->Init( cBase ); } pSlab->SetThickness( 5 ); pSlab->SetVerticalOffset( 0 ); pSlab->SetHorizontalOffset( 0 ); pSlab->SetPivotPoint( OdGePoint3d::kOrigin ); AECDisplayManager cDM( pDatabase ); AECDbDispPropsSlabPtr pOverrideModel = AECDbDispPropsSlab::cast( pSlab->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepSlabModel::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverrideModel.isNull() ) { pOverrideModel->GetBoundaryCompByIndex( 0 )->SetColor( colorAt( 1 ) ); pOverrideModel->GetBaselineComp()->SetColor( colorAt( 4 ) ); pOverrideModel->GetPivotPointComp()->SetColor( colorAt( 5 ) ); pOverrideModel->GetFasciaComp()->SetColor( colorAt( 6 ) ); pOverrideModel->GetSoffitComp()->SetColor( colorAt( 7 ) ); pOverrideModel->GetShrinkWrapBodyComp()->SetColor( colorAt( 8 ) ); } AECDbDispPropsSlabPlanPtr pOverridePlan = AECDbDispPropsSlabPlan::cast( pSlab->OverrideDispProps( cDM.UpdateDisplayRepresentation( AECDbDispRepSlabPlan::desc() ) ).openObject( OdDb::kForWrite ) ); if ( !pOverridePlan.isNull() ) { pOverridePlan->SetIsOverrideCutPlane( false ); pOverridePlan->GetHatchComp()->SetColor( colorAt( 1 ) ); pOverridePlan->GetBelowCutPlaneBodyComp()->SetColor( colorAt( 2 ) ); pOverridePlan->GetAboveCutPlaneBodyComp()->SetColor( colorAt( 3 ) ); pOverridePlan->GetBelowCutPlaneOutlineComp()->SetColor( colorAt( 4 ) ); pOverridePlan->GetAboveCutPlaneOutlineComp()->SetColor( colorAt( 5 ) ); } } class MyServices : public ExSystemServices, public ExHostAppServices { protected: ODRX_USING_HEAP_OPERATORS(ExSystemServices); }; int wmain(int argc, wchar_t* argv[]) { // Initialize TD with system services. // And create single instance of hostapp services // for TD database creation. OdStaticRxObject<MyServices> svcs; odInitialize( &svcs ); odgsInitialize(); // Loading of all public Teigha Architecture DRX modules. // Note that not all calls are necessary for some of them depend on others // but here we list all of them. // // If a program uses TD doesn't modify or create binary files // it may not load any of DRX modules on start because they will be loaded automatically. // But if a program modifies or creates binary files then it is highly recommended // to load all DRX modules program uses. ::odrxDynamicLinker()->loadApp( OD_T("AecBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecArchBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecArchDACHBase") ); ::odrxDynamicLinker()->loadApp( OD_T("AecScheduleData") ); ::odrxDynamicLinker()->loadApp( OD_T("AecSchedule") ); ::odrxDynamicLinker()->loadApp( OD_T("AecStructureBase") ); // Create empty TD database. OdDbDatabasePtr pDatabase = svcs.createDatabase();; // Initialize database with default Teigha Architecture content. AECArchDACHBaseDatabase( pDatabase ).Init(); AECScheduleDatabase( pDatabase ).Init(); AECStructureBaseDatabase( pDatabase ).Init(); init_display_system( pDatabase ); OdDbObjectId idWallStyle = add_wall_style( pDatabase ); OdDbObjectId idWall1 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 0, 0 ), OdGePoint2d( 0, 110 ) ); OdDbObjectId idWall2 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 0, 110 ), OdGePoint2d( 110, 110 ) ); OdDbObjectId idWall3 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 110, 110 ), OdGePoint2d( 110, 0 ) ); OdDbObjectId idWall4 = add_wall( pDatabase, idWallStyle, OdGePoint2d( 110, 0 ), OdGePoint2d( 0, 0 ), -1 ); AECDbWallPtr ptWall = AECDbWall::cast( idWall1.openObject( OdDb::kForRead ) ); OdDbObjectId idWindowStyle = add_window_style( pDatabase ); OdDbObjectId idWindow01 = add_window( pDatabase, idWindowStyle, idWall1, 10, 10 ); OdDbObjectId idWindow02 = add_window( pDatabase, idWindowStyle, idWall1, 60, 10 ); OdDbObjectId idWindow03 = add_window( pDatabase, idWindowStyle, idWall1, 10, 60 ); OdDbObjectId idWindow04 = add_window( pDatabase, idWindowStyle, idWall1, 60, 60 ); OdDbObjectId idWindow05 = add_window( pDatabase, idWindowStyle, idWall2, 10, 10 ); OdDbObjectId idWindow06 = add_window( pDatabase, idWindowStyle, idWall2, 60, 10 ); OdDbObjectId idWindow07 = add_window( pDatabase, idWindowStyle, idWall2, 10, 60 ); OdDbObjectId idWindow08 = add_window( pDatabase, idWindowStyle, idWall2, 60, 60 ); OdDbObjectId idWindow09 = add_window( pDatabase, idWindowStyle, idWall3, 10, 10 ); OdDbObjectId idWindow10 = add_window( pDatabase, idWindowStyle, idWall3, 60, 10 ); OdDbObjectId idWindow11 = add_window( pDatabase, idWindowStyle, idWall3, 10, 60 ); OdDbObjectId idWindow12 = add_window( pDatabase, idWindowStyle, idWall3, 60, 60 ); OdDbObjectId idProfile = add_profile_def( pDatabase ); OdDbObjectId idDoorStyle = add_door_style( pDatabase, idProfile ); AECDbWallPtr pWall = idWall4.openObject( OdDb::kForRead ); double dLength = pWall->GetLength(); double dOWidth = 40; double dL1 = 10; double dL3 = dLength - dOWidth - 10; double dL2 = dL1 + dOWidth + (dL3 - (dL1 + 2 * dOWidth)) / 2; OdDbObjectId idDoor = add_door ( pDatabase, idDoorStyle, idWall4, dL2, 0 ); OdDbObjectId idWindow13 = add_window ( pDatabase, idWindowStyle, idWall4, dL1, 10 ); OdDbObjectId idWindow14 = add_window ( pDatabase, idWindowStyle, idWall4, dL3, 10 ); OdDbObjectId idWindow15 = add_window ( pDatabase, idWindowStyle, idWall4, dL1, 60 ); OdDbObjectId idWindow16 = add_window ( pDatabase, idWindowStyle, idWall4, dL2, 60 ); OdDbObjectId idOpening = add_window ( pDatabase, idWindowStyle, idWall4, dL3, 60 ); add_roof(pDatabase); add_slab(pDatabase); // Perform "zoom extents" on model space. { OdDbViewportTablePtr pVT = pDatabase->getViewportTableId().openObject( OdDb::kForRead ); OdDbViewportTableRecordPtr pV = pVT->getActiveViewportId().openObject( OdDb::kForWrite ); pV->zoomExtents(); } OdWrFileBuf cBuffer( "H:\\TA_test.dwg" ); pDatabase->writeFile( &cBuffer, OdDb::kDwg, OdDb::kDHL_CURRENT ); odgsUninitialize(); odUninitialize(); return 0; }
      
      









まとめ



Teighaを使用して、空のデータベースを作成し、建築オブジェクトと連動するように初期化し、最も使用されるタイプのオブジェクトをいくつか作成し、これらすべてを最新の形式のdwgファイルに正常に保存しました。

もちろん、私は多くの側面を非常に表面的に単純化して説明しましたが、この記事の目的は単にTAの機能を示し、dighgファイルとAutoCADオブジェクトを操作する別の機会としてTeighaの一般的なアイデアを与えることです。



All Articles