多角形を四角形に変換する
四角形を多角形に変換するコマンドは、デフォルトのメニュー・コマンドにあるのですが、その逆はありません。不可逆変換なのです(笑)。四角形は、中心をスナップすることができる点が便利なので、時々多角形を四角形にわざわざ描き替えたりしていましたが、結構そういう機会があるので、コーディングしてみました。このコマンドは、多角形を四角形に変換するためのものです。 ※オブジェクトタイプが曲線で、頂点数が4の場合(多角形の辺を非表示にしているときなど)にも対応しました。
最近 Vectorworks 2011 にバージョンアップしたのですが、四角形のデータ形式が変わって傾いても四角形というデータタイプを保持できるようになりました。(たぶん 2008 からだと思うのですが・・・考えてみれば、Vectorworks の四角形の定義は、数学上の正方形か長方形のことですよね。)下記がフローです。
- 多角形の頂点数が4かどうかをチェック > GetVertNum
- 4点の座標を取得 > GetPolyPt
- 隣り合う辺のなす角が直角か?3つ調べれば良い > DotProduct でベクトル変数を直接計算
- 許容精度を設ける。S=1/50 の図面で、1E-008(0.00000001)程度。
- 多角形(曲線)の頂点インデックスは右回りと左回りがあるので、2Dの外積の正負で判定する。
- RectangleN で描画する。
- 元の多角形の属性を GET し、新たに描画した四角形に SET する。
以下ソースです。注意点として、Ver.2010 以前の場合は、48行目の GetTypeN > GetType に変更してください。
また、プラグインコマンド編集ダイアログのパラメータボタンをクリックして、以下のように登録してください。
- 名前:RAccuracy
- フィールド名:許容精度
- 型:Number
- 初期値:1E-008(縮尺 1/50程度の場合です。縮尺によって数値を調整してください。
{*******************************************************************************
ChangeRectangle
多角形を四角形に変換する
Copyright 2010 兵藤善紀建築設計事務所
www.hyodo-arch.com 2010.04.14
2011.10.18 Ver 0.21 許容精度の判定に絶対値ABS関数を使う。
2011.10.03 Ver 0.20 角度属性に対応。
2010.06.10 Ver 0.13 曲線に対応
2010.04.14 Ver 0.12 複数図形を選択しているときにも処理させる努力
2010.04.14 Ver 0.11 クラス属性に対応させる努力
2010.04.14 Ver 0.10 まず最初のバージョン
*******************************************************************************}
PROCEDURE ChangeRect;
CONST
ObjectsOpt = 2; {ForEach~のパラメータ。選択図形を操作}
TraversalOpt = 1; {ForEach~のパラメータ。グループ内も操作}
LayersOpt = 4; {ForEach~のパラメータ。編集可能なレイヤを操作}
VAR
RAccuracy :REAL; {許容精度}
ObjTypeMess :String; {ダイアログ用メッセージ}
{**************************** ChangeRectangle 四角形に変換 ****************************}
FUNCTION ChangeRectangle(hh:handle):boolean;
VAR
Rhh :Handle; {ハンドル, hh:選択図形、Rhh:新たに描いた四角形}
NumOfVertex :Integer; {多角形の頂点の数}
PolyPt:ARRAY[1..4] OF Vector; {頂点座標用配列}
RDP:ARRAY[1..4] OF REAL; {内積格納用配列}
Raa,Rbb :Vector; {外積を調べるベクトル}
RRotation :REAL; {外積から多角形の頂点が右回り 左回りを判定}
ii :Integer; {カウンタ}
hhClass :String; {クラス名}
hhRed:ARRAY[1..4] OF Longint; {面と線のRed値}
hhGreen:ARRAY[1..4] OF Longint; {面と線のGreen値}
hhBlue:ARRAY[1..4] OF Longint; {面と線のBlue値}
hhFPat :Longint; {模様の番号}
hhLS, hhLW :Integer; {線の種類。線の太さ}
BEGIN
NumOfVertex:=GetVertNum(hh);
IF ((GetTypeN(hh)=5) | (GetTypeN(hh)=21)) AND (NumOfVertex=4) THEN
Begin
FOR ii:=1 TO NumOfVertex DO GetPolyPt(hh,ii,PolyPt[ii].x,PolyPt[ii].y);
RDP[1]:=DotProduct(PolyPt[2]-PolyPt[1],PolyPt[4]-PolyPt[1]); {内積が 0 なら直角。3つの角を調べる}
RDP[2]:=DotProduct(PolyPt[3]-PolyPt[2],PolyPt[1]-PolyPt[2]);
RDP[3]:=DotProduct(PolyPt[4]-PolyPt[3],PolyPt[2]-PolyPt[3]);
{ObjTypeMess:=Concat('RDP[1] = ',RDP[1],' RDP[2] = ',RDP[2],' RDP[3] = ',RDP[3]);
AlrtDialog(ObjTypeMess);}
If (
( Abs(RDP[1])0 then RRotation:=1 else RRotation:=-1;
RectangleN (
PolyPt[1].x,PolyPt[1].y,
Raa.x,Raa.y,
Distance(PolyPt[2].x,PolyPt[2].y,PolyPt[1].x,PolyPt[1].y),
RRotation*Distance(PolyPt[4].x,PolyPt[4].y,PolyPt[1].x,PolyPt[1].y)
);
Rhh:=LNewObj;
hhClass:=GetClass(hh); {クラス名の取得}
GetFillFore (hh,hhRed[1],hhGreen[1],hhBlue[1]); {面の色の取得}
GetFillBack (hh,hhRed[2],hhGreen[2],hhBlue[2]); {面の地色の取得}
GetPenFore (hh,hhRed[3],hhGreen[3],hhBlue[3]); {線の色の取得}
GetPenBack (hh,hhRed[4],hhGreen[4],hhBlue[4]); {線の地色の取得}
hhFPat:=GetFPat(hh); {模様の取得}
hhLS:=GetLS(hh); {線の種類の取得}
hhLW:=GetLW(hh); {線の太さの取得}
SetClass(Rhh,hhClass); {クラス名の設定}
if IsFillColorByClass(hh) then {******** 面の色 ********}
SetFillColorByClass(Rhh) {クラス属性を使用している場合の設定}
else
begin {クラス属性を使用していない場合の設定}
SetFillFore (Rhh,hhRed[1],hhGreen[1],hhBlue[1]); {面の色の設定}
SetFillBack (Rhh,hhRed[2],hhGreen[2],hhBlue[2]); {面の地色の設定}
end;
if IsFPatByClass(hh) then {******** 模様 ********}
SetFPatByClass(Rhh) {クラス属性を使用している場合の設定}
else SetFPat(Rhh,hhFPat); {クラス属性を使用していない場合の設定}
if IsPenColorByClass(hh) then {******** 線の色 ********}
SetPenColorByClass(Rhh) {クラス属性を使用している場合の設定}
else
begin
SetPenFore (Rhh,hhRed[3],hhGreen[3],hhBlue[3]); {線の色の設定}
SetPenBack (Rhh,hhRed[4],hhGreen[4],hhBlue[4]); {線の地色の設定}
end;
if IsLSByClass(hh) then {******** 線の種類 ********}
SetLSByClass(Rhh) {クラス属性を使用している場合の設定}
else SetLS(Rhh,hhLS); {クラス属性を使用していない場合の設定}
if IsLWByClass(hh) then {******** 線の太さ ********}
SetLWByClass(Rhh) {クラス属性を使用している場合の設定}
else SetLW(Rhh,hhLW); {クラス属性を使用していない場合の設定}
DelObject(hh); {元の多角形を削除}
{ObjTypeMess:=Concat(' hhRed[1] = ',hhRed[1],' hhRed[2] = ',hhRed[2],' hhRed[3] = ',hhRed[3]);
AlrtDialog(ObjTypeMess);}
end;
End;
{ELSE
Begin
ObjTypeMess:=Concat('選択されていた図形を四角形に変換することはできませんでした。Object Type = ',Num2StrF(GetType(hh)),' 頂点の数=',NumOfVertex);
AlrtDialog(ObjTypeMess);
End;}
END;{****************** ChangeRectangle 四角形に変換 END******************}
BEGIN
RAccuracy:=PRACCURACY; {許容誤差。プラグインコマンド編集>パラメータ で 名前:RAccuracy、フィールド名:許容精度、型:Number、初期値:1E-008 としておく。}
ForEachObjectInLayer(ChangeRectangle,ObjectsOpt,TraversalOpt,LayersOpt);
{Message('SelectObjLayer=',SelectObjLayer,' SelectObjClass=',SelectObjClass);}
END;
RUN ( ChangeRect );
以下に Ver.12.5 までのソースも置いておきます。
{*******************************************************************************
ChangeRectangle
多角形を四角形に変換する
Copyright 2010 兵藤善紀建築設計事務所
www.hyodo-arch.com 2010.04.14
2010.06.10 Ver 0.13 曲線に対応
2010.04.14 Ver 0.12 複数図形を選択しているときにも処理させる努力
2010.04.14 Ver 0.11 クラス属性に対応させる努力
2010.04.14 Ver 0.10 まず最初のバージョン
*******************************************************************************}
PROCEDURE ChangeRect;
CONST
ObjectsOpt = 2; {ForEach~のパラメータ。選択図形を操作}
TraversalOpt = 1; {ForEach~のパラメータ。グループ内も操作}
LayersOpt = 4; {ForEach~のパラメータ。編集可能なレイヤを操作}
VAR
ObjTypeMess :String; {ダイアログ用メッセージ}
{**************************** ChangeRectangle 四角形に変換 ****************************}
FUNCTION ChangeRectangle(hh:handle):boolean;
VAR
Rhh :Handle; {ハンドル, hh:選択図形、Rhh:新たに描いた四角形}
NumOfVertex :Integer; {多角形の頂点の数}
PolyPt:ARRAY[1..4] OF Vector; {クラスID 用配列}
ii :Integer; {カウンタ}
hhClass :String; {クラス名}
hhRed:ARRAY[1..4] OF Longint; {面と線のRed値}
hhGreen:ARRAY[1..4] OF Longint; {面と線のGreen値}
hhBlue:ARRAY[1..4] OF Longint; {面と線のBlue値}
hhFPat :Longint; {模様の番号}
hhLS :Integer; {線の種類}
hhLW :Integer; {線の太さ}
BEGIN
NumOfVertex:=GetVertNum(hh);
IF ((GetType(hh)=5) | (GetType(hh)=21)) AND (NumOfVertex=4) THEN
Begin
FOR ii:=1 TO NumOfVertex DO GetPolyPt(hh,ii,PolyPt[ii].x,PolyPt[ii].y);
If (
(PolyPt[1].x=PolyPt[4].x) AND (PolyPt[1].y=PolyPt[2].y)
AND (PolyPt[3].x=PolyPt[2].x) AND (PolyPt[3].y=PolyPt[4].y)
)
OR (
(PolyPt[1].x=PolyPt[2].x) AND (PolyPt[1].y=PolyPt[4].y)
AND (PolyPt[3].x=PolyPt[4].x) AND (PolyPt[3].y=PolyPt[2].y)
)
Then
begin
Rect(PolyPt[1].x,PolyPt[1].y,PolyPt[3].x,PolyPt[3].y);
Rhh:=LNewObj;
hhClass:=GetClass(hh); {クラス名の取得}
GetFillFore (hh,hhRed[1],hhGreen[1],hhBlue[1]); {面の色の取得}
GetFillBack (hh,hhRed[2],hhGreen[2],hhBlue[2]); {面の地色の取得}
GetPenFore (hh,hhRed[3],hhGreen[3],hhBlue[3]); {線の色の取得}
GetPenBack (hh,hhRed[4],hhGreen[4],hhBlue[4]); {線の地色の取得}
hhFPat:=GetFPat(hh); {模様の取得}
hhLS:=GetLS(hh); {線の種類の取得}
hhLW:=GetLW(hh); {線の太さの取得}
SetClass(Rhh,hhClass); {クラス名の設定}
if IsFillColorByClass(hh) then {******** 面の色 ********}
SetFillColorByClass(Rhh) {クラス属性を使用している場合の設定}
else
begin {クラス属性を使用していない場合の設定}
SetFillFore (Rhh,hhRed[1],hhGreen[1],hhBlue[1]); {面の色の設定}
SetFillBack (Rhh,hhRed[2],hhGreen[2],hhBlue[2]); {面の地色の設定}
end;
if IsFPatByClass(hh) then {******** 模様 ********}
SetFPatByClass(Rhh) {クラス属性を使用している場合の設定}
else SetFPat(Rhh,hhFPat); {クラス属性を使用していない場合の設定}
if IsPenColorByClass(hh) then {******** 線の色 ********}
SetPenColorByClass(Rhh) {クラス属性を使用している場合の設定}
else
begin
SetPenFore (Rhh,hhRed[3],hhGreen[3],hhBlue[3]); {線の色の設定}
SetPenBack (Rhh,hhRed[4],hhGreen[4],hhBlue[4]); {線の地色の設定}
end;
if IsLSByClass(hh) then {******** 線の種類 ********}
SetLSByClass(Rhh) {クラス属性を使用している場合の設定}
else SetLS(Rhh,hhLS); {クラス属性を使用していない場合の設定}
if IsLWByClass(hh) then {******** 線の太さ ********}
SetLWByClass(Rhh) {クラス属性を使用している場合の設定}
else SetLW(Rhh,hhLW); {クラス属性を使用していない場合の設定}
DelObject(hh); {元の多角形を削除}
end;
End;
{ELSE
Begin
ObjTypeMess:=Concat('選択されていた図形を四角形に変換することはできませんでした。Object Type = ',Num2StrF(GetType(hh)),' 頂点の数=',NumOfVertex);
AlrtDialog(ObjTypeMess);
End;}
END;{****************** ChangeRectangle 四角形に変換 END******************}
BEGIN
ForEachObjectInLayer(ChangeRectangle,ObjectsOpt,TraversalOpt,LayersOpt);
{Message('SelectObjLayer=',SelectObjLayer,' SelectObjClass=',SelectObjClass);}
END;
RUN ( ChangeRect );