「文字セット」の改良からはじまったVectorScript

よく何度も編集した図面を印刷すると、寸法線の文字がそろっていないというミスに気付くことがありました。
そんな時「文字セット」が便利でしたが、このツールには不満もありました(現在は2010用のものが無償公開されています)。
そこで、これを改良できないかというのが、私のVectorScriptへの入り口となりました。
まず、フォントとサイズ以外は変更することがないので、あとの設定についてはバッサリと切り落としました。
ですので、問題はフォントとサイズに絞ります。

(内容は一部のみ)

CONST
	kTextNode = 10;		{文字列}
	kDimensionNode = 63;	{寸法線}

	kDimFont = 28;	{寸法文字のフォント番号}
	kDimSize = 40;	{寸法値のフォントサイズ}
VAR
	fontName:STRING;
	size:REAL;
	textH:HANDLE;

IF GetType(textH) = kTextNode THEN
BEGIN
	SetTextFont ( textH, 0, GetTextLength ( textH ), GetFontID ( fontName ) );
	SetTextSize ( textH, 0, GetTextLength ( textH ), size );
END;

IF GetType(textH) = kDimensionNode THEN
BEGIN
	SetObjectVariableInt ( textH, kDimFont, GetFontID( fontName ) );
	SetObjectVariableReal ( textH, kDimSize, size );
END;

IF ( GetType ( textH ) = 86 ) & ( GetName ( GetRecord ( textH, NumRecords ( textH ) ) ) = 'NNA_ChainDim' ) THEN
BEGIN
	SetObjectVariableInt ( textH, kDimFont, GetFontID ( fontName ) );
	SetObjectVariableReal ( textH, kDimSize, size );
END;

このツールでは、文字列、寸法線に加えて、直列寸法線を対象にしているのですが、実際には働かないことが分かっています。
何故なのかを調べてみると、 直列寸法線が属性値=[40]の値を持たないことが分かります。
しかし、フォントサイズにはもう一つ属性値=[17]があり、両者の違いは単位がポイントかミリかで、こちらは値があると分かりました。
換算は、1インチ=25.4mm、72ポイント=1インチとなります。
また、ミリでは、ポイントでは必要のないスケールを考慮する必要があるようです。
直列寸応線以外のプラグインオブジェクト[TYPE=86]でも、例えば、引き出し線[PON=Callout]なども対象にしたいと考えます。
プラグインオブジェクトは、属性値=[800]で「フォントメニューの設定を利用する」かどうかを判定することができます。
これが、TRUEの場合、属性値=[17]が存在することが分かりました。
ただし、これが有効であってもデータパレットで別に設定できる「図面枠」のようなものは、設定変更できない事も分かっています。
記述も、IF文よりCASE文の方が適しているので、書き直すと。

(内容は一部のみ)

CONST
	kTextNode = 10;		{文字列}
	kDimensionNode = 63;	{寸法線}
	kPLUGINOBJECT = 86;	{プラグインオブジェクト}

	kDimFont = 28;		{寸法文字のフォント番号}
	kDimSize = 40;		{寸法値のフォントサイズ}
	kDimSize_mm = 17;	{寸法値のフォントサイズ(mm)}
VAR
	fontName:STRING;
	size:REAL;
	textH:HANDLE;

CASE GetType(textH) OF
	kTextNode:
	BEGIN
		SetTextFont ( textH, 0, GetTextLength ( textH ), GetFontID ( fontName ) );
		SetTextSize ( textH, 0, GetTextLength ( textH ), size );
	END;

	kDimensionNode:
	BEGIN
		SetObjectVariableInt ( textH, kDimFont, GetFontID( fontName ) );
		SetObjectVariableReal ( textH, kDimSize, size );
	END;

	kPLUGINOBJECT:
		IF GetObjectVariableBoolean(textH,800) = TRUE THEN
		BEGIN
			SetObjectVariableInt ( textH, kDimFont, GetFontID( fontName ) );
			SetObjectVariableReal ( textH, kDimSize_mm, (size/72*25.4*GetLScale(ActLayer)) );
		END;
END;

もう少し調べてみると、文字列専用のコマンドSetTextFontをもつ「文字列」も、属性値=[28]をもつことや、寸法線しか属性値=[40]をもたないのに対し、属性値=[17]はいずれもがもつことが分かりました。
つまり、すべての対象オブジェクトは、属性値=[28]と[17]で一括して処理できるわけです。

次に疑問を持ったのが、グループに入った状態ではスクリプトが働かないことです。
特に、ビューポート注釈内で「寸法線」を処理できないのが不満でした。
このスクリプトは、レイヤ上のオブジェクトしか対象にしていないのです。
グループ内のオブジェクトののハンドルは、FInGroupで最上位のハンドルで取得した後、NextObjまたはNextSObjで取得していきます。
ビューポート注釈内は、GetVPGroupでビューポートのハンドルから注釈グループのハンドルを取得して、FInGroupで。

他にも、シンボル内は、GetSymNameでシンボルの名前を取り、同名のシンボル定義をSetActSymbolでアクティブ(選択状態)にして、アクティブなシンボル定義(ActSymDef)内をFInSymDefで。
ソリッドモデラー内は、FIn3Dで取得できます。
また、NextObjNextSObjPrevObjPrevSObjは、最初に指定したハンドルのある範囲を超えてはいくことはありません。
グループ内の処理方法が分かると、標準機能では一括で処理されてしまうグループ内のオブジェクトも、スクリプトなら分別して処理可能だと分かります。

その次に問題となるのが、グループに入るなど現在の表示状態をどう判断させるのかです。
実は、グループなどに入っている状態では、原則FSActLayerが1つになります。
「前の画面」を利用すると確認することができます。
このことは、意図的にこの原則を崩してしまえることにもなるのですが、通常の使い方では早々陥らないでしょうが、DSelectAllを実行することで確実にできます。
DSelectAllはグループの外へは働かないという特徴があります。
すべての選択を解除するには、DSelectObj(ALL & INVIEWPORT)などが必要になります。

話はそれますが、その一方でSelectObjは、グループの内外を分別できません。
最初、オブジェクトの選択には図形選択マクロを使っていましたが、これには問題があることが分かり、選択するスクリプトも必要と考えるようになりました。
例えば、グループ内に入った状態で図形選択マクロを使って選択した後、「文字セット」を使うとグループの外にあるレイヤ上の対象オブジェクトだけが処理されるという、一見不思議な現象が起きます。
同様に、NumObjCountにも動作の範囲に癖があるので、注意が必要です。

話は元に戻りますが、先の現在の表示状態の判定方法は、選択状態からスタートするスクリプトでは使えないことが分かります。
そこで便利なのがForEachObjectInLayerです。
このコマンドは、処理範囲が標準ツールと同じになる特徴がある上、処理関数によって標準ツールではできない分別も可能になります。
処理関数の返値はFALSEの場合、対象のオブジェクトを続けて処理し、TRUEの場合、1つでだけ終了します。
例えば、アクティブなハンドルを1つ取得するためだけ使うことも可能で、このような場合はTRUEを返せばいいわけです。
ただ、シートレイヤ上からは、ビューポート注釈内のオブジェクトをターゲットにはしません。
グループの一種とされているビューポートですが、実際の扱いはシンボルに近いです。

(内容は一部のみ)

CONST
	kDimFont = 28;		{寸法文字のフォント番号}
	kDimSize_mm = 17;	{寸法値のフォントサイズ(mm)}
VAR
	fontName:STRING;
	size:REAL;
	V_scale:REAL;

FUNCTION Change_TextSetF(textH:HANDLE):BOOLEAN;
BEGIN
	IF Selected(textH) THEN	{グループ内の選択を分別するには必要}
	BEGIN
		IF IsVPGroupContainedObject(textH,2) THEN V_scale:=GetObjectVariableReal(FSActLayer,1003)
			ELSE V_scale:=GetLScale(ActLayer);

		SetObjectVariableInt(textH,kDimFont,GetFontID(fontName));
		SetObjectVariableReal(textH,kDimSize_mm,(size/72*25.4*V_scale));

		ResetObject(textH);
	END;

	Change_TextSetF:=FALSE;	
END;

BEGIN
	ForEachObjectInLayer(Change_TextSetF,2,1,0);
	{objOptions:Selected travOptions:Groups layerOptions:Current}
END;

他に似たようなコマンドとして、ForEachObjectForEachObjectInListがありますが、ForEachObjectは図面上のすべてのオブジェクトを一括処理するのに向き、ForEachObjectInListはレイヤ上とグループ内の処理を分けたい場合、グループの再帰処理などに向きます。

このように1つのスクリプトの手直しが、いくつもの新規スクリプト作成へとどんどん拡大していくこととなっていきました。
具体的には、各スクリプトの内容を参照していただければと思います。