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.