CAD日記

主にAutoCADのことについて書いているけど、近頃は投資系ネタに注力している。自動売買、仮想通貨、PC関係、プログラミングなど。@caddiary

ソフト開発 AutoCAD

AutoCADのクリッピング情報を語る

投稿日:

AutoCADのクリッピング情報は様々あって、代表的なものとしてレイアウトのビューポート枠によってモデルの絵をクリッピングするというのがある。モデルをのぞき込む窓がビーポートであって、そいつにはレンズがあって1/100どかのサイズに縮めることができる。ビューポート枠は矩形(長方形)が一般的だが、多角形やら入り組んだ形状にすることもできる。モデルの絵をビューポート枠で切り取ることになるからクリッピング。矩形で線分を切り取るんだったら単純で、始点または終点が短くなるだけで済む。しかし、ギザギザの形状をしたビューポート枠の上に線分が乗っていたら、複数の線分が破線上に連なる。。という具合に単純ではない。

ビューポート以外のクリッピング情報とは何か?ブロックのXCLIPがそう。メニュー操作的には修正⇒クリップ⇒外部参照。ブロック配置情報(INSERT)ごとに、その表示エリアを限定することができる。ブロック配置に対してクリップできるというのがポイントで、ブロック定義には影響ない。同名で複数のブロックを配置した際に、その配置したものごとにどこを切り取るのかを変えられる。このブロックを分解するとクリップ情報が消えてしまうため、クリップによって見えない箇所が現れてしまうという問題がある。クリップされた状態で分解するべきだろうにね。

イメージもクリッピングできる。図面に画像を配置するにあたって、画像自体で必要なところだけにクリッピングしておけばいいがそんなことせずとも、配置したイメージにクリッピング情報を付加して切り取る。同様にビューポートも可能。ビューポート自体がすでにクリッピングしているところにさらにクリッピングするというVPCLIPなるもの。

AutoCADのクリッピング情報について文章で語るとこんなもの。これだけではつまらんので、dwgデータ構造をODA(旧Teigha)で参照したときにどうなっているかをコードも交えながら解説していく。クリッピング枠がどんなデータ構造で持たれているのかということでもあり、少し前に書いたハッチング枠とも近い存在。閉じた領域を形づくっているもので、必ず閉じていなかればいけない。必ず閉じているということなら円や楕円がシンプルだが、やっぱ直線で構成された長方形が一般的。線分4つで長方形にすると頂点部分がつながっているかという問題が出やすい。よってポリラインの登場だ。4つの頂点を持っていて閉じるフラグが立っていれば間違いなく閉じた領域になる。頂点情報にふくらみを与えれば途中に円弧を交えることだってできてしまう。ポリラインってスゲーなと思う次第。

・ビューポート(VIEWPORT)
クラス名OdDbViewport。エンティティの一種として定義されており、円やら円やらと同じ仲間。centerPoint()、viewCenter()、viewTarget()によって座標を得られ、これらとheight()、width()からビューポート枠の形状がわかる。isNonRectClipOn()の場合はレクトではなく、nonRectClipEntityId()で得たOdDbObjectIdからOdDbEntityを取得した結果が円か楕円かポリラインが2Dポリラインとなる。図形1つで構成されているからシンプル。ハッチング枠が複数の図形で構成されていてやっかいなのとは対照的。

・ブロックのクリップ(XCLIP)
クラス名OdGiClipBoundary。ブロック配置つまりINSERTのクラス名OdDbBlockReferenceから取得する。ここは簡単じゃないのでコードを引用する。

OdDbBlockReference* pSrc;
...
OdDbSpatialFilterPtr pFilt;
pFilt = OdDbIndexFilterManager::getFilter( pSrc, OdDbSpatialFilter::desc(), OdDb::kForRead );
if( !pFilt.get() )
	return( FALSE );
if( !pFilt->isEnabled() )
	return( FALSE );
bool enabled = 0; 
pFilt->getDefinition( *pDef, enabled );

OdGePoint3d poss = pSrc->position();
OdGeMatrix3d toWorld = pSrc->blockTransform() * pDef->m_xInverseBlockRefXForm * pDef->m_xToClipSpace.inverse();

pDef->m_Pointsというのがクリップする座標配列なので、上記で得られたtoWorldで座標変換(transformBy)する。昔自分で書いたコードを振り返ってみているが、何をやってんだかよくわからん。。
ともあれクリップ枠の座標がわかったので、ブロックを分解した結果の図形をその枠で切り取ればよい。切り取るっつっても、図形が枠内に完全に入っていれば切り取らずにそのまま変換するし、完全に入っていなければ変換しない。そのどちらでもない(部分的に入っている場合)に、切り取り処理を通す。

・イメージのクリップ(IMAGECLIP)
専用のクラスはなく、イメージそのもののクラスOdDbRasterImageからクリップ情報を取得する。
以下でコードをがっつりと引用する。イメージがクリップ情報を持っているときに、ビューポートのクリップ情報とANDを取って改めてイメージのクリップ情報を再セットする感じ。マトリックスによる座標変換を何度かしており、複雑怪奇。ベースはODAをサンプルコードから持ってきてはいるが、よくぞこんなコードが書けたもんだと感心。

OdDbRasterImage* pDst;
...
if( !pDst->isClipped() )
	pDst->setClipBoundaryToWholeImage();
OdGePoint2dArray ary = pDst->clipBoundary();
if( ary.size() < 2 )
	return( TRUE );
else if( ary.size() == 2 )
{
	OdGePoint2d p1 = ary.getAt(0);
	OdGePoint2d p2 = ary.getAt(1);
	ary.clear();
	ary.append( p1 );
	ary.append( OdGePoint2d(p2.x, p1.y) );
	ary.append( p2 );
	ary.append( OdGePoint2d(p1.x, p2.y) );
	ary.append( p1 );
}
OdGeMatrix3d mrx3 = pDst->getPixelToModelTransform();
double elv = 0;
OdGeMatrix2d mrx2 = mrx3.convertToLocal( OdGeVector3d(0,0,1), elv );
CArray<DPOINT,DPOINT> aryDp;
for( UINT i=0; i<ary.size(); i++ )
{
	OdGePoint2d pnt = ary.getAt(i);
	pnt.transformBy( mrx2 );
	DPOINT dpo = {pnt.x, pnt.y};
	aryDp.Add( dpo );
}
short ecnt = 0;
short pcnt = 0;
DPOINT* pPnt = new DPOINT[1000];
if( !GeoAndArea( pVp->iPoly, pVp->pPoly, aryDp.GetSize(), aryDp.GetData(), 1, 1000, &ecnt, &pcnt, pPnt, ZERO ) || ecnt == 0 )
{
	delete pPnt;
	return( TRUE );
}
ary.clear();
for( int j=0; j<pcnt; j++ )
{
	OdGePoint2d pnt( pPnt[j].x, pPnt[j].y );
	pnt.transformBy( mrx2.inverse() );
	ary.append( pnt );
}
delete pPnt;
pDst->setClipBoundary( ary );
pDst->setDisplayOpt( OdDbRasterImage::kClip, true );

AutoCADのクリッピング情報、おもしろい。前述した「AutoCADでブロックを分解するとクリップ情報が消える」という件があるから、AutoCADのカスタマイズコマンドとして「クリップ情報を生かしたブロック分解」のカスタマイズコマンドを作ってみようか。。ブロック分解を完全に自前で行う必要があるから、容易でないのは確か。ブロックはネスト構造になっていて、そのネスト構造の中にクリップ情報があることが分かっているし、内部参照だけでなく外部参照のブロックだって考慮する必要あり。10年前だったらコツコツと作りはじめたかもしれないが、もうすぐ52歳になろうとしているおいらなので、十中八九構想のみで終わるだろう。

-ソフト開発, AutoCAD

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事

クリップボード履歴を一括でまとめて取得したいだろ?

Windows 10 1809の新機能「クリップボード履歴」はそこそこ使えるんだけど、惜しいんだよね。最大25個までのコピーした履歴を取れるところまではよいが、その履歴を一括でまとめて取得できないのだ …

no image

UnicodeとAutoCAD

AutoCAD 2007のDXFとDWGでは、文字がUnicodeコード化されてるんだって。 試しに、2007で「あいうえお」って文字を書いて、2007のDXFで保存して テキストエディタで見たら、め …

PDFiumViewerのソースコード

GitHubで公開されているPDFiumViewerのソースコードをダウンロードして、PDFiumそのものの使い勝手を調査いていたが、なかなか困難な取り組みであり、頓挫しているところ。 PDFiumV …

インフラSEへの道~マジックパケットを送信してマシンを起動する~

Wake On LANを試してみようと以下の記事を書いたわけだが、PowerShellでマジックパケットを送信しようとしたところ、PowerShellのセキュリティや文字コードがややこしいと感じて、自 …

PDFアレコレで画面の拡大・縮小・移動ができるようにした

PDFアレコレをバージョンアップ。約4か月ぶり。 Ver3.05 2021/6/20 ・PDFの描画位置を左右上下にセンタリングするようにした(以前は左上)。 ・Ctrl+マウスホイール上下操作によっ …