Bricscad V13-V19 (BJ-Electrical) 線番数取得、リレー接点集計ツール
2019/01/03 選択セットの取得を修正(ソースコードのみの変更)
2018/12/21 V19に対応。線番のシート名のソート、重複を除外を追加 (Ver.13)
2017/08/19 リレー接点の集計を追加 (Ver.1.2)
Bricscad で開いているすべての図面から、線番を取得し、作成数を表示するツールです。
※外部から操作している (Delphi - ActiveX) ので、かなり遅いです。
・Canon チューブプリンタツール Mk2500PC 用のCSVファイルが作成できます。
・配線、線番を画面の中央に表示し、△マークで指示します。
・これにより、線番の無い配線、複数の線番がある場合も、見つけやすいです。
※配線上に線番が無いときは、端子記号が線番として採用されます。

・配線、線番を画面の中央に表示し、△マークで指示します。

・リレーの接点数を集計して、属性に書き込みます。(Ver.1.2)
C接点は、a接点、b接点の線番によって判断しています。(ピン番号は無視)

■ダウンロード BcadSenban.zip (Ver.1.3 exe本体のみ)
2019/01/03 選択セットの取得を変更
unit BcadSenbanUnit;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, BricscadApp_TLB, BricscadDb_TLB, ComObj,
Vcl.StdCtrls, Vcl.Grids, Vcl.ComCtrls, Vcl.Menus, Vcl.ExtDlgs, System.UITypes,
Vcl.Buttons;
type
LineCheck = record
LineId : integer;
Checked : boolean;
end;
SenbanId = record
ObjectId : integer;
DocumentId : integer;
end;
type
TForm3 = class(TForm)
Button1: TButton;
StringGrid1: TStringGrid;
ProgressBar1: TProgressBar;
Label1: TLabel;
Label2: TLabel;
MainMenu1: TMainMenu;
N1: TMenuItem;
CSV1: TMenuItem;
SaveTextFileDialog1: TSaveTextFileDialog;
SpeedButton1: TSpeedButton;
Edit1: TEdit;
UpDown1: TUpDown;
UpDown2: TUpDown;
SpeedButton2: TSpeedButton;
Edit2: TEdit;
SpeedButton3: TSpeedButton;
SpeedButton4: TSpeedButton;
SpeedButton5: TSpeedButton;
SpeedButton6: TSpeedButton;
Button2: TButton;
N2: TMenuItem;
N3: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
N6: TMenuItem;
N7: TMenuItem;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure CSV1Click(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure StringGrid1Click(Sender: TObject);
procedure UpDown1Click(Sender: TObject; Button: TUDBtnType);
procedure SpeedButton2Click(Sender: TObject);
procedure UpDown2Click(Sender: TObject; Button: TUDBtnType);
procedure SpeedButton3Click(Sender: TObject);
procedure SpeedButton4Click(Sender: TObject);
procedure SpeedButton5Click(Sender: TObject);
procedure SpeedButton6Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure N3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
RunFlag : boolean;
//
procedure DrawLineMarker(LineFlag: boolean);
end;
var
Form3: TForm3;
// 線分の端点同士がつながる線分を一時的に保持
LineIdAry : array of LineCheck;//integer;
// 線分上の交点を一時的に保持
KoutenIdAry : array of integer;
SenbanStrAry : array of string;
SenbanIdAry : array of SenbanId;
// 線分上の線番を一時的に保持
// 線分チェック済を保持
LineCheckAry : array of LineCheck;
function GetLineLineStart(doc : AcadDocument ; line : AcadLine) : integer;
implementation
{$R *.dfm}
procedure SgSortByCol2(sg : TStringGrid; col1, col2 :integer; NumFlag:boolean);
// StringGrid ソート
var
i, j : integer;
sl, sltemp : TStringList;
s1, s0 : string;
begin
// ソート
sl := TStringList.Create;
try
sltemp := TStringList.Create;
try
with sg do begin
for i := 1 to RowCount -2 do begin
s0 := '';
if col1 >= 0 then s0 := s0 + Cells[col1, i];
if col2 >= 0 then s0 := s0 + Cells[col2, i];
for j := i + 1 to RowCount -1 do begin
s1 := '';
if col1 >= 0 then s1 := s1 + Cells[col1, j];
if col2 >= 0 then s1 := s1 + Cells[col2, j];
if (not NumFlag and (s0 > s1)) or
(NumFlag and (StrToIntDef(s0, 0) > StrToIntDef(s1, 0))) then begin
slTemp.Assign(Rows[i]);
Rows[i] := Rows[j];
Rows[j] := slTemp;
s0 := s1;
end;
end;
end;
end;
finally
slTemp.Free;
end;
finally
sl.Free;
end;
end;
procedure PointToPolygon(vpt : OleVariant; faz: double; var vpts: OleVariant);
// Point vpt を囲う四角形を返す
begin
vpts[0] := vpt[0] - faz;
vpts[1] := vpt[1] + faz;
vpts[2] := 0;
vpts[3] := vpt[0] + faz;
vpts[4] := vpt[1] + faz;
vpts[5] := 0;
vpts[6] := vpt[0] + faz;
vpts[7] := vpt[1] - faz;
vpts[8] := 0;
vpts[9] := vpt[0] - faz;
vpts[10] := vpt[1] - faz;
vpts[11] := 0;
end;
procedure StEdToFence(stpt, edpt :OleVariant; var vpts: OleVariant);
// 2座標をFence座標に
var
i : integer;
begin
// 線分の始点-終点をポイントリストに
for i := 0 to 2 do vpts[i] := stpt[i];
for i := 0 to 2 do vpts[i + 3] := edpt[i];
end;
function AddLineIdAry(objId : integer): integer;
var
i, n: integer;
flag : boolean;
begin
n := Length(LineIdAry);
if n = 0 then begin
SetLength(LineIdAry, n + 1);
with LineIdAry[n] do begin
LineId := objId;
Checked := False;
end;
end
else begin
flag := false;
for i := 0 to n -1 do begin
// すでに存在
if LineIdAry[i].LineId = objId then begin
flag := True;
break;
end;
end;
if not flag then begin
SetLength(LineIdAry, n + 1);
with LineIdAry[n] do begin
LineId := objId;
Checked := False;
end;
end;
end;
result := Length(LineIdAry);
end;
function AddKoutenIdAry(objId : integer): integer;
var
i, n: integer;
flag : boolean;
begin
n := Length(KoutenIdAry);
if n = 0 then begin
SetLength(KoutenIdAry, n + 1);
KoutenIdAry[n] := objId;
end
else begin
flag := false;
for i := 0 to n -1 do begin
// すでに存在
if KoutenIdAry[i] = objId then begin
flag := True;
break;
end;
end;
if not flag then begin
SetLength(KoutenIdAry, n + 1);
KoutenIdAry[n] := objId;
end;
end;
result := Length(KoutenIdAry);
end;
function Distance(vpt1, vpt2 : OleVariant): double;
// 2点間の2D距離
begin
result := sqrt((vpt1[0] - vpt2[0]) * (vpt1[0] - vpt2[0])
+ (vpt1[1] - vpt2[1]) * (vpt1[1] - vpt2[1]));
end;
function GetLineLine(doc : AcadDocument) : integer;
// LineIdAry の線分の端点に接続する線分を取得
var
line : AcadLine;
i : integer;
pts : OleVariant;
begin
if Length(LineIdAry) > 0 then begin
pts := VarArrayCreate([0, 11], varDouble);
for i := 0 to Length(LineIdAry) - 1 do begin
// 最初に検出した線分は除外する
if not LineIdAry[i].Checked then begin
line := doc.ObjectIdToObject(LineIdAry[i].LineId) as AcadLine;
GetLineLineStart(doc, line);
end;
end;
end;
result := Length(LineIdAry);
end;
{
// ss := doc.ActiveSelectionSet; が使えるため、コメントアウト。使用しない
procedure MakeSelectionSet(doc : AcadDocument; const ssName : string; var ss : AcadSelectionSet);
// 選択セットを作成
var
i : integer;
ssets : AcadSelectionSets;
flag : boolean;
begin
flag := False;
ssets :=doc.SelectionSets;
if ssets.Count > 0 then begin
for i := 0 to ssets.Count - 1 do begin
if ssets.Item(i).Name = ssName then begin
ss := ssets.Item(i);
ss.Clear;
flag := True;
end;
end;
end;
if not flag then
ss := ssets.Add(ssName);
end;
}
function GetKoutenLine(doc : AcadDocument): integer;
// KoutenIdAryの交点マークに交差する線分を取得
var
i, j : integer;
filterType, filterData: OleVariant;
pts : OleVariant;
ss : AcadSelectionSet;
blkref : AcadBlockReference;
begin
pts := VarArrayCreate([0, 11], varDouble);
// フィルターを作成
filterType := VarArrayCreate([0, 2], varSmallInt);
filterData := VarArrayCreate([0, 2], varVariant);
filterType[0] := 8; // 画層
filterData[0] := 'WIRE';
filterType[1] := 0; // 図形
filterData[1] := 'LINE';
filterType[2] := 62; // 色
filterData[2] := '256';
// セレクションセットを取得
ss := doc.ActiveSelectionSet;
if Length(KoutenIdAry) > 0 then begin
for i := 0 to Length(KoutenIdAry) - 1 do begin
blkref := doc.ObjectIdToObject(KoutenIdAry[i]) as AcadBlockReference;
PointToPolygon(blkref.InsertionPoint, 0.1 , pts);
ss.SelectByPolygon(acSelectionSetCrossingPolygon, pts, filterType, filterData);
if ss.Count > 0 then begin
for j := 0 to ss.Count - 1 do
AddLineIdAry(ss.Item(j).ObjectID);
end;
end;
end;
result := Length(LineIdAry);
end;
function GetLineKouten(doc : AcadDocument): integer;
// LineIdAry の線分上の交点を取得
var
line : AcadLine;
i, j, n : integer;
filterType, filterData: OleVariant;
pts : OleVariant;
ss : AcadSelectionSet;
begin
pts := VarArrayCreate([0, 5], varDouble);
// フィルターを作成
filterType := VarArrayCreate([0, 2], varSmallInt);
filterData := VarArrayCreate([0, 2], varVariant);
filterType[0] := 8; // 画層
filterData[0] := 'WIRE';
filterType[1] := 0; // 図形
filterData[1] := 'INSERT';
filterType[2] := 2; // 名前
filterData[2] := 'CMARK';
// セレクションセットを取得
ss := doc.ActiveSelectionSet;
n := Length(LineIdAry);
if n > 0 then begin
for i := 0 to n - 1 do begin
line := doc.ObjectIdToObject(LineIdAry[i].LineId) as AcadLine;
StEdToFence(line.StartPoint, line.EndPoint, pts);
ss.SelectByPolygon(acSelectionSetFence, pts, filterType, filterData);
if ss.Count > 0 then begin
for j := 0 to ss.Count - 1 do
AddKoutenIdAry(ss.Item(j).ObjectID);
end;
end;
end;
result := Length(KoutenIdAry);
end;
function GetLineLineStart(doc : AcadDocument; line : AcadLine) : integer;
// 線分の端点につながる線分を取得
// 線分数を返す
var
ss : AcadSelectionSet;
j, k : integer;
pta, ptb : OleVariant;
pts : OleVariant;
stpt, edpt : OleVariant;
n : integer;
d1,d2 : double;
lineId : integer;
filterType, filterData: OleVariant;
begin
// セレクションセットを取得
ss := doc.ActiveSelectionSet;
// 4点の3D座標リスト(配列数=4×3,添え字の上限 = 11)
pts := VarArrayCreate([0, 11], varDouble);
// フィルターを作成
filterType := VarArrayCreate([0, 2], varSmallInt);
filterData := VarArrayCreate([0, 2], varVariant);
filterType[0] := 8; // 画層
filterData[0] := 'WIRE';
filterType[1] := 0; // 図形
filterData[1] := 'LINE';
filterType[2] := 62; // 色
filterData[2] := '256'; // BYLAYER
pta := line.StartPoint;
ptb := line.EndPoint;
lineId := line.ObjectID;
AddLineIdAry(lineId);
for k := 0 to 1 do begin
while True do begin
PointToPolygon(pta, 0.1, pts);
ss.Clear;
ss.SelectByPolygon(acSelectionSetCrossingPolygon, pts, filterType, filterData);
// 自分自身だけであれば終了
if ss.Count < 2 then break;
n := Length(LineIdAry);
for j := 0 to ss.Count - 1 do begin
if ss.Item(j).ObjectID <> lineId then begin
line := ss.Item(j) as AcadLine;
stpt := line.StartPoint;
edpt := line.EndPoint;
d1 := Distance(pta, stpt);
d2 := Distance(pta, edpt);
// 端点同士がつながる線分のみ
if (d1 <= 0.1) or (d2 <= 0.1) then begin
AddLineIdAry(ss.Item(j).ObjectID);
// 次の端点を見つける
if d1 <= 0.1 then pta := edpt
else pta := stpt;
// 基準線分を更新
lineId := line.ObjectID;
end;
// 1つ見つかれば終了
break;
end;
end;
// 新規に取得できなければ終了(念のため)
if n = Length(LineIdAry) then break;
end;
pta := ptb;
end;
ss.Clear;
result := Length(LineIdAry);
end;
procedure AddSenbanStr(const senban :string);
// 線番を一時的に保持
var
i, n : integer;
flag : boolean;
begin
flag := false;
n := Length(SenbanStrAry);
// すでに存在するか
if n > 0 then begin
for i := 0 to n - 1 do begin
if senban = SenbanStrAry[i] then begin
flag := True;
break;
end;
end;
end;
// 追加
if not flag then begin
SetLength(SenbanStrAry, n + 1);
SenbanStrAry[n] := senban;
end;
end;
function GetSenbanTextString(blkref : AcadBlockReference): string;
// ブロックから線番文字列を得る
// 属性名=SENBAN
var
atts : OleVariant;
att : AcadAttributeReference;
i : integer;
idisp : IDispatch;
begin
result := '';
if blkref.HasAttributes then begin
atts := blkref.GetAttributes;
for i := 0 to VarArrayHighBound(atts, 1) do begin
idisp := atts[i];
att := idisp as AcadAttributeReference;
if att.TagString = 'SENBAN' then begin
result := att.TextString;
break;
end;
end;
end;
end;
function GetSenban(doc : AcadDocument; docId :integer): string;
// 線上の線番を取得
var
i, n, m : integer;
line : AcadLine;
stpt, edpt, pts : OleVariant;
ss : AcadSelectionSet;
filterType, filterData : OleVariant;
blkref : AcadBlockReference;
j : Integer;
d1 , d2 : double;
s : string;
begin
result := '';
// フェンス選択のための3D座標リスト
pts := VarArrayCreate([0, 5], varDouble);
// フィルターを作成
filterType := VarArrayCreate([0, 2], varSmallInt);
filterData := VarArrayCreate([0, 2], varVariant);
filterType[0] := 8; // 画層
filterData[0] := '*SENBAN*';
filterType[1] := 0; // 図形
filterData[1] := 'INSERT';
filterType[2] := 2; // 図形
filterData[2] := '*SENBAN*';
n := Length(LineIdAry);
if n > 0 then begin
// セレクションセットを取得
ss := doc.ActiveSelectionSet;
for i := 0 to n - 1 do begin
line := doc.ObjectIdToObject(LineIdAry[i].LineId) as AcadLine;
stpt := line.StartPoint;
edpt := line.EndPoint;
// 横線
if abs(stpt[0] - edpt[0]) > abs(stpt[1] - edpt[1]) then begin
// 線分の上側
stpt[1] := stpt[1] + 2.0;
edpt[1] := edpt[1] + 2.0;
end
else begin
// 線分の左側
stpt[0] := stpt[0] - 2.0;
edpt[0] := edpt[0] - 2.0;
end;
StEdToFence(stpt, edpt, pts);
ss.SelectByPolygon(acSelectionSetFence, pts, filterType, filterData);
if ss.Count > 0 then begin
for j := 0 to ss.Count - 1 do begin
blkref := ss.Item(j) as AcadBlockReference;
d1 := Distance(blkref.InsertionPoint, line.StartPoint);
d2 := Distance(blkref.InsertionPoint, line.EndPoint);
// 挿入起点が、ほぼ線上点
if abs((d1 + d2) - Distance(line.StartPoint, line.EndPoint)) < 0.1 then begin
// 線番の文字列を取得
s := GetSenbanTextString(blkref);
// 線番を保持
if s <> '' then begin
m := Length(SenbanIdAry);
SetLength(SenbanIdAry, m + 1);
with SenbanIdAry[m] do begin
ObjectId := blkref.ObjectID;
DocumentId := docId;
end;
AddSenbanStr(s);
end;
end;
end;
end;
end;
end;
n := Length(SenbanStrAry);
if n > 0 then begin
for i := 0 to n - 1 do begin
if i = 0 then result := SenbanStrAry[i]
else result := result + ',' + SenbanStrAry[i];
end;
end;
end;
function GetTbTextString(blkref : AcadBlockReference): string;
// ブロックから端子番号を得る
// 属性名=NAME + NAME1
var
atts : OleVariant;
att : AcadAttributeReference;
i : integer;
idisp : IDispatch;
begin
result := '';
if blkref.HasAttributes then begin
atts := blkref.GetAttributes;
for i := 0 to VarArrayHighBound(atts, 1) do begin
idisp := atts[i];
att := idisp as AcadAttributeReference;
with att do begin
if TagString = 'NAME' then
result := TextString
else
if TagString = 'NAME1' then begin
result := result + TextString;
break;
end;
end;
end;
end;
end;
function GetTbNo(doc : AcadDocument; docId: integer): string;
// 線分の端点につながる端子番号を取得
var
i, n, m : integer;
line : AcadLine;
stpt, edpt, pts : OleVariant;
ss : AcadSelectionSet;
filterType, filterData : OleVariant;
blkref : AcadBlockReference;
j, k : Integer;
s : string;
begin
result := '';
// フェンス選択のためのポイントリスト
pts := VarArrayCreate([0, 11], varDouble);
// フィルターを作成
filterType := VarArrayCreate([0, 2], varSmallInt);
filterData := VarArrayCreate([0, 2], varVariant);
filterType[0] := 8; // 画層
filterData[0] := '*WIRE*';
filterType[1] := 0; // 図形
filterData[1] := 'INSERT';
filterType[2] := 2; // 図形
filterData[2] := 'INCIR*,OUTCIR*';
n := Length(LineIdAry);
if n > 0 then begin
// セレクションセットを取得
ss := doc.ActiveSelectionSet;
for i := 0 to n - 1 do begin
line := doc.ObjectIdToObject(LineIdAry[i].LineId) as AcadLine;
stpt := line.StartPoint;
edpt := line.EndPoint;
for k := 0 to 1 do begin
PointToPolygon(stpt, 0.1, pts);
ss.SelectByPolygon(acSelectionSetCrossingPolygon, pts, filterType, filterData);
if ss.Count > 0 then begin
for j := 0 to ss.Count - 1 do begin
blkref := ss.Item(j) as AcadBlockReference;
// 端子番号の文字列を取得
s := GetTbTextString(blkref);
// 線番として保持
if s <> '' then begin
m := Length(SenbanIdAry);
SetLength(SenbanIdAry, m + 1);
with SenbanIdAry[m] do begin
ObjectId := blkref.ObjectID;
DocumentId := docId;
end;
AddSenbanStr(s);
end;
end;
end;
stpt := edpt;
ss.Clear;
end;
end;
end;
n := Length(SenbanStrAry);
if n > 0 then begin
for i := 0 to n - 1 do begin
if i = 0 then result := SenbanStrAry[i]
else result := result + ',' + SenbanStrAry[i];
end;
end;
end;
procedure LineCheckMark;
// 線分処理済みをチエック
var
i, j : integer;
n, m : integer;
begin
n := Length(LineIdAry);
m := Length(LineCheckAry);
if (n > 0) and (m > 0) then begin
for i := 0 to n - 1 do begin
for j := 0 to m - 1 do begin
if LineIdAry[i].LineId = LineCheckAry[j].LineId then begin
LineCheckAry[j].Checked := True;
break;
end;
end;
end;
end;
end;
function GetSheetNo(doc : AcadDocument): string;
// 図枠ブロック TITLE からシート番号を得る
// 属性名=ZSHEET
var
i, k, n, m : integer;
ss : AcadSelectionSet;
filterType, filterData : OleVariant;
blkref : AcadBlockReference;
attr : OleVariant;
att : AcadAttributeReference;
idisp : IDispatch;
lays : AcadLayers;
lay : AcadLayer;
flag : boolean;
begin
result := '';
flag := false;
// 画層ロック中は選択できないため、ロックを解除
lays := doc.Layers;
for i := 0 to lays.Count - 1 do begin
if lays.Item(i).Name = 'TITLE' then begin
lay := lays.Item(i);
lay.Lock := false;
flag := True;
break;
end;
end;
// フィルターを作成
filterType := VarArrayCreate([0, 2], varSmallInt);
filterData := VarArrayCreate([0, 2], varVariant);
filterType[0] := 8; // 画層
filterData[0] := 'TITLE';
filterType[1] := 0; // 図形
filterData[1] := 'INSERT';
filterType[2] := 2; // 図形
filterData[2] := 'TITLE';
// セレクションセットを取得
ss := doc.ActiveSelectionSet;
ss.Select(acSelectionSetAll, EmptyParam, EmptyParam, filterType, filterData);
if ss.Count > 0 then begin
blkref := ss.Item(0) as AcadBlockReference;
if (blkref.Name = 'TITLE') and blkref.HasAttributes then begin
attr := blkref.GetAttributes;
n := VarArrayLowBound(attr, 1);
m := VarArrayHighBound(attr, 1);
for k := n to m do begin
// 個々の属性を取得
idisp := attr[k];
att := idisp as AcadAttributeReference;
if 'ZSHEET' = att.TagString then begin
Result := att.TextString;
Break;
end;
end;
end;
end;
// 画層ロックを戻す
if flag then lay.Lock := True
end;
procedure SenbanSeiri(sg : TStringGrid);
// 同じ線番で整理する
var
i, j, n : integer;
begin
with sg do begin
if RowCount > 2 then begin
n := RowCount;
for i := n - 1 downto 2 do begin
if (Cells[2, i] <> '') and (Cells[2, i] = Cells[2, i - 1]) then begin
Cells[0, i - 1] := Cells[0, i - 1] + ',' + Cells[0, i];
// シート名
Cells[1, i - 1] := Cells[1, i - 1] + ',' + Cells[1, i];
// 作成数
Cells[3, i - 1] := IntToStr(
StrToIntDef(Cells[3, i - 1], 0) + StrToIntDef(Cells[3, i], 0) - 2);
// DocID
Cells[6, i - 1] := Cells[6, i - 1] + ',' + Cells[6, i];
// ObjectID
Cells[7, i - 1] := Cells[7, i - 1] + ',' + Cells[7, i];
// DocID
Cells[8, i - 1] := Cells[8, i - 1] + ',' + Cells[8, i];
// SenbanID
Cells[9, i - 1] := Cells[9, i - 1] + ',' + Cells[9, i];
for j := i to RowCount - 2 do Rows[j] := Rows[j + 1];
RowCount := RowCount - 1;
end;
end;
end;
end;
end;
procedure TForm3.Button1Click(Sender: TObject);
var
app : AcadApplication;
docs : AcadDocuments;
doc : AcadDocument;
ss : AcadSelectionSet;
filterType, filterData: OleVariant;
i, j, k : integer;
line : AcadLine;
linecnt : integer;
cmarkcnt : integer;
cnt : integer;
s : string;
limmax, limmin : OleVariant;
sgcnt : integer;
sht : string;
Ticks : Cardinal;
s1, s2 : string;
ret : boolean;
begin
try
if not Supports(GetActiveOleObject('BricscadApp.AcadApplication'), AcadApplication, app) then begin
ShowMessage('サポートされていない');
exit;
end;
except
ShowMessage('有効な BricsCAD が見つかりません.');
exit;
end;
ret := MessageDlg('CADから線番情報を取得しますか?', mtInformation , [mbYes, mbNo], 0) = mrYes;
if not ret then exit;
Ticks := GetTickCount;
Button1.Enabled := False;
Button2.Enabled := True;
RunFlag := True;
// フィルターを作成
filterType := VarArrayCreate([0, 2], varSmallInt);
filterData := VarArrayCreate([0, 2], varVariant);
filterType[0] := 8; // 画層
filterData[0] := 'WIRE';
filterType[1] := 0; // 図形
filterData[1] := 'LINE';
filterType[2] := 62; // 色
filterData[2] := '256'; // BYLAYER
sgcnt := 0;
docs := app.Documents;
// BeginUpdate
SendMessage(StringGrid1.Handle, WM_SETREDRAW, 0, 0);
try
// SG 初期化
with StringGrid1 do begin
RowCount := 2;
Row := 1;
for k := 0 to ColCount - 1 do Cells[k, 1] := '';
end;
for k := 0 to docs.Count - 1 do begin
Application.ProcessMessages;
if not RunFlag then break;
doc := docs.Item(k);
with doc do begin
// 念のためREGEN
Regen(acActiveViewport);
// 選択範囲(図枠の外は除外するため)
limmin := GetVariable('LIMMIN');
limmax := GetVariable('LIMMAX');
Label1.Caption :=
'[ ' + IntToStr(k + 1) + ' / ' + IntToStr(docs.Count)+ ' ] '+ Name;
end;
// シート番号
sht := GetSheetNo(doc);
// セレクションセットを取得
ss := doc.ActiveSelectionSet;
ss.Select(acSelectionSetWindow, limmin, limmax, filterType, filterData);
if ss.Count > 0 then begin
ProgressBar1.Max := ss.Count;
// 線分チェックを用意
SetLength(LineCheckAry, ss.Count);
for i := 0 to ss.Count - 1 do begin
with LineCheckAry[i] do begin
LineId := ss.Item(i).ObjectID;
Checked := false;
end;
end;
// テンポラリを初期化
SetLength(LineIdAry, 0);
SetLength(KoutenIdAry, 0);
SetLength(SenbanStrAry, 0);
SetLength(SenbanIdAry, 0);
for i := 0 to ss.Count - 1 do begin
Application.ProcessMessages;
if not RunFlag then break;
Label2.Caption := IntToStr(i + 1) + ' / ' + IntToStr(ss.Count);
ProgressBar1.StepIt;
if not LineCheckAry[i].Checked then begin
line := ss.Item(i) as AcadLine;
// 端点同士つながる線分を取得
GetLineLineStart(doc, line);
// チェック済にする
if Length(LineIdAry) > 0 then begin
for j := 0 to Length(LineIdAry) - 1 do
LineIdAry[j].Checked := True;
end;
cnt := 0;
while True do begin
Application.ProcessMessages;
if not RunFlag then break;
linecnt := Length(LineIdAry);
// その線分上の交点マークを取得
GetLineKouten(doc);
cmarkcnt := Length(KoutenIdAry);
// 交点マークに掛かる線分を取得
GetKoutenLine(doc);
// その線分上の交点マークを取得
GetLineKouten(doc);
// 交点マークに掛かる線分を取得
GetKoutenLine(doc);
// その端点につながる線分を取得
// 検出済みの線分は除外
GetLineLine(doc);
// チェック済にする
if Length(LineIdAry) > 0 then begin
for j := 0 to Length(LineIdAry) - 1 do
LineIdAry[j].Checked := True;
end;
// 追加分がなければ終了
if (linecnt = Length(LineIdAry)) and (cmarkcnt = Length(KoutenIdAry)) then
break;
// 念のため、10回程度で終了(無限ループよけ)
Inc(cnt);
if cnt > 10 then break;
end;
// 処理済みにチェックマークを付ける
LineCheckMark;
// 線分上の線番を取得(','があれば、異なる線番がある)
s := GetSenban(doc, k);
// 線番が無ければ、端子番号を取得
if s = '' then s := GetTbNo(doc, k);
Inc(sgcnt);
with StringGrid1 do begin
if RowCount < sgcnt + 1 then
RowCount := sgcnt + 1;
Cells[0, sgcnt] := IntToStr(sgcnt);
// シート番号
Cells[1, sgcnt] := sht;
// 線番
Cells[2, sgcnt] := s;
// 作成数
Cells[3, sgcnt] := IntToStr((Length(KoutenIdAry) + 1) * 2);
// DocID
Cells[6, sgcnt] := IntToStr(k);
// ObjectID (線分の代表)
Cells[7, sgcnt] := IntToHex(line.ObjectID, 8);
if Length(SenbanIdAry) > 0 then begin
for j := 0 to Length(SenbanIdAry) - 1 do begin
s1 := IntToStr(SenbanIdAry[j].DocumentId);
s2 := IntToHex(SenbanIdAry[j].ObjectId, 8);
if j = 0 then begin
// 線番DocID
Cells[8, sgcnt] := s1;
// 線番ObjectID
Cells[9, sgcnt] := s2;
end
else begin
Cells[8, sgcnt] := Cells[8, sgcnt] + ',' + s1;
Cells[9, sgcnt] := Cells[9, sgcnt] + ',' + s2;
end;
end;
end;
end;
// テンポラリを初期化
SetLength(LineIdAry, 0);
SetLength(KoutenIdAry, 0);
SetLength(SenbanStrAry, 0);
SetLength(SenbanIdAry, 0);
end;
end;
SetLength(LineCheckAry, 0);
ss.Clear;
end;
end;
// ソート
SgSortByCol2(StringGrid1, 2, -1, false);
// 同じ線番を整理
SenbanSeiri(StringGrid1);
finally
// EndUpdate
SendMessage(StringGrid1.Handle, WM_SETREDRAW, 1, 0);
StringGrid1.Refresh;
end;
ProgressBar1.Position := 0;
Label1.Caption := '';
Label2.Caption := '';
ShowMessage('終了しました.(' + Format('%.1f', [(GetTickCount - Ticks) / 1000]) + ' sec)');
Button2.Enabled := False;
Button1.Enabled := True;
end;
procedure TForm3.Button2Click(Sender: TObject);
begin
RunFlag := False;
Application.ProcessMessages;
end;
procedure TForm3.CSV1Click(Sender: TObject);
// CSV 保存
var
sl : TStringList;
i : integer;
fname : TFIleName;
ret : boolean;
begin
if StringGrid1.RowCount <= 2 then exit;
if SaveTextFileDialog1.Execute then begin
fname := SaveTextFileDialog1.FileName;
if Uppercase(ExtractFileExt(fname)) <> '.CSV' then
fname := fname + '.csv';
ret := True;
if FileExists(fname) then
ret := MessageDlg('すでに存在します.上書きしますか?',
mtInformation , [mbYes, mbNo], 0) = mrYes;
if ret then begin
with StringGrid1 do begin
//if RowCount > 2 then begin
sl := TStringList.Create;
try
for i := 1 to RowCount - 1 do
sl.Add(Cells[2, i] + ',,,' + Cells[3, i]);
sl.SaveToFile(fname);
finally
sl.Free;
end;
//end;
end;
end;
end;
end;
procedure TForm3.FormCreate(Sender: TObject);
begin
Button2.Enabled := False;
Label1.Caption := '';
Label2.Caption := '';
with StringGrid1 do begin
ColCount := 10;
Cells[0, 0] := 'No.';
Cells[1, 0] := 'シート';
Cells[2, 0] := '線番';
Cells[3, 0] := '作成数';
Cells[4, 0] := '1行目';
Cells[5, 0] := '2行目';
Cells[6, 0] := 'DocID';
Cells[7, 0] := 'ObjectID';
Cells[8, 0] := 'DocId';
Cells[9, 0] := 'SenbanID';
ColWidths[0] := 120;
ColWidths[1] := 200;
ColWidths[2] := 60;
ColWidths[3] := 60;
// 非表示
ColWidths[4] := -1;
ColWidths[5] := -1;
ColWidths[6] := -1;
ColWidths[7] := -1;
ColWidths[8] := -1;
ColWidths[9] := -1;
RowCount := 2;
Row := 1;
end;
end;
procedure TForm3.N3Click(Sender: TObject);
begin
Close;
end;
procedure TForm3.DrawLineMarker(LineFlag : boolean);
// 線番マーク
var
app : AcadApplication;
doc : AcadDocument;
h, hnd : THandle;
ARect : TRect;
cx, cy : integer;
dc : HDC;
screensize : OleVariant;
winsc : double;
docId : integer;
objId : integer;
ret : boolean;
line : AcadLine;
blkref : AcadBlockReference;
pt : OleVariant;
i : integer;
cel1, cel2 : integer;
idx : integer;
sl : TStringList;
sbnon : boolean;
begin
try
if not Supports(GetActiveOleObject('BricscadApp.AcadApplication'),
AcadApplication, app) then begin
ShowMessage('サポートされていない');
exit;
end;
except
ShowMessage('有効な BricsCAD が見つかりません.');
exit;
end;
// 線番がない
with StringGrid1 do sbnon := Cells[8, Row] = '';
// 線分マーク
if LineFlag or sbnon then begin
cel1 := 6;
cel2 := 7;
idx := UpDown1.Position - 1;
end
else begin
// 線番マーク
cel1 := 8;
cel2 := 9;
idx := UpDown2.Position - 1;
end;
sl := TStringList.Create;
try
with StringGrid1 do begin
sl.CommaText := Cells[cel1, Row];
if (sl.Count > 0) and (sl.Count> idx) then
docId := StrToIntDef(sl[idx] , -1)
else docId := -1;
sl.CommaText := Cells[cel2, Row];
if (sl.Count > 0) and (sl.Count> idx) then
objId := StrToIntDef('$' + sl[idx], -1)
else objId := -1;
ret := (docId >= 0) and (objId > 0);
end;
finally
sl.Free;
end;
if ret then begin
doc := app.Documents.Item(docId);
if app.ActiveDocument <> doc then begin
doc.Activate;
Sleep(100);
end;
pt := VarArrayCreate([0, 1], VarDouble);
try
if LineFlag or sbnon then begin
line := doc.ObjectIdToObject(objId) as AcadLine;
// 中点
for i := 0 to 1 do
pt[i] := (line.StartPoint[i] + line.EndPoint[i]) / 2.0;
end
else begin
blkref := doc.ObjectIdToObject(objId) as AcadBlockReference;
// 挿入起点
for i := 0 to 1 do pt[i] := blkref.InsertionPoint[i];
end;
// ズーム
app.ZoomCenter(pt, 220.0);
// システム変数を取得
screensize := doc.GetVariable('SCREENSIZE');
h := GetWindow(app.HWND, GW_CHILD);
h := GetWindow(h, GW_CHILD);
// グラフィックウィンドウのハンドル
// クラス名は、バージョンにより異なる(V13 の場合は、下記)
hnd := FindWindowEx(h, 0, 'AfxFrameOrView100u', nil);
if not IsWindow(hnd) then
hnd := FindWindowEx(h, 0, 'AfxFrameOrView110u', nil);
if not IsWindow(hnd) then
hnd := FindWindowEx(h, 0, 'AfxFrameOrView120u', nil);
if IsWindow(hnd) then begin
// グラフィックウィンドウの矩形座標
GetWindowRect(hnd, ARect);
winsc := screensize[0] / (ARect.Right - ARect.Left);
// グラフィック画面の中心座標
cx := (ARect.Right - ARect.Left) div 2;
cy := (Arect.Bottom - ARect.Top) div 2;
cx := Trunc(cx * winsc);
cy := Trunc(cy * winsc);
// ウィンドウのデバイスコンテキストを取得
dc := GetDC(hnd);
// デバイスコンテキストの前景モードを反転色にする
if GetROP2(dc) <> R2_NOT then SetROP2(dc, R2_NOT);
// 三角形を描く
MoveToEx(dc, cx, cy, nil);
LineTo(dc, cx - 30, cy + 15);
LineTo(dc, cx - 15, cy + 30);
LineTo(dc, cx, cy);
// デバイスコンテキストを解放
ReleaseDC(hnd, dc);
end
else
ShowMessage('グラフィックウィンドウ取得失敗');
except
;
end;
end;
end;
procedure TForm3.SpeedButton1Click(Sender: TObject);
// 線番マーク >
begin
with StringGrid1 do begin
if Row < RowCount - 1 then Row := Row + 1
else Row := 1;
end;
DrawLineMarker(True);
end;
procedure TForm3.SpeedButton2Click(Sender: TObject);
begin
with StringGrid1 do begin
if Row > 1 then Row := Row - 1
else Row := RowCount - 1;
end;
DrawLineMarker(True);
end;
procedure TForm3.SpeedButton3Click(Sender: TObject);
begin
with StringGrid1 do begin
if Row < RowCount - 1 then Row := Row + 1
else Row := 1;
end;
DrawLineMarker(False);
end;
procedure TForm3.SpeedButton4Click(Sender: TObject);
begin
with StringGrid1 do begin
if Row > 1 then Row := Row - 1
else Row := RowCount - 1;
end;
DrawLineMarker(False);
end;
procedure TForm3.SpeedButton5Click(Sender: TObject);
begin
DrawLineMarker(True);
end;
procedure TForm3.SpeedButton6Click(Sender: TObject);
begin
DrawLineMarker(False);
end;
procedure TForm3.StringGrid1Click(Sender: TObject);
var
sl : TStringList;
begin
sl := TStringList.Create;
try
with StringGrid1 do
sl.CommaText := Cells[7, Row];
with UpDown1 do begin
Max := sl.Count;
Position := Max;
end;
with StringGrid1 do
sl.CommaText := Cells[9, Row];
with UpDown2 do begin
Max := sl.Count;
Position := Max;
end;
finally
sl.Free;
end;
end;
procedure TForm3.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
// 複数線分群
DrawLineMarker(True);
end;
procedure TForm3.UpDown2Click(Sender: TObject; Button: TUDBtnType);
begin
// 線番
DrawLineMarker(false);
end;
end.