こちらの続きです。
外部ファイルから点を3Dに取り込む2 - C#ATIA
こちらも過去に "Unofficial CATIA User Forum" でUpしたものです。
前回のマクロでも目的は達成できるのですが、大量の点を取り込む際
どうしても時間がかかり過ぎます。
これに悩み、思いついたのが "CSVファイルから点のみのIgesファイルを作成" と
言う方法でした。
当時はC#も覚え始めで、静的クラスやらLinq等も理解できぬまま作ったもの
ですし、Igesの仕様を調べながらだったので、見るも無残なソースコードです。
//cs using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.IO; namespace csv2igs { class Program { //D&D public static int Main(string[] args) { string[] txts; switch (args.Length) { case 0: Msgbox("csv又はxyzファイルをD&Dしてください"); break; case 1: txts = LoadFile(args[0]); if (txts != null) { //読み込みOK var inDir = Path.GetDirectoryName(args[0]); var inFExt = Path.GetFileNameWithoutExtension(args[0]); char splitword = ','; switch (Path.GetExtension(args[0]).ToUpper()) { case ".XYZ": splitword = ' '; break; default: //csvを想定 splitword = ','; break; } var igs = new Iges(); igs.SetSplitWord(splitword); var expfname = createFileName(inDir, inFExt, ""); var exDir = Path.GetDirectoryName(expfname); var exFil = Path.GetFileName(expfname); var pntcount = igs.expIges(txts, inFExt, exDir, exFil); var msg = expfname + "\r\n" + "を作成しました" + "\r\n" + "ポイント数は" + pntcount.ToString() + "です"; MessageBox.Show(msg, "終了", MessageBoxButtons.OK); } else { Msgbox("ファイルの読み込みが出来ませんでした"); } break; default: Msgbox("D&Dは1ファイルにしてください"); break; } return 0; } //ファイルの読み込み static string[] LoadFile(string fpath) { //ファイルの読み込み StreamReader reader = null; try { // ファイルを開いて中身を表示 reader = new StreamReader(fpath, System.Text.Encoding.GetEncoding("Shift_JIS")); string text = reader.ReadToEnd(); text = text.ToUpper(); // 配列に分割 string[] texts = text.Replace("\r\n", "\n").Split('\n'); return texts; } catch (Exception e) { // エラー処理 // ファイルが存在しなかったり、アクセス権限がない場合にここが実行される。 Console.Write(e.Message + "\n"); return null; } finally { // 後処理 if (reader != null) reader.Close(); } } //重複しないファイル名を取得 static string createFileName(string sDir, string sFExt, string num) { //この辺、標準で機能ないのかな? string stemp = "_"; if (num == "") { stemp = ""; } if (File.Exists(sDir + @"/" + sFExt + stemp + num + ".igs")) { if (num == "") { num = "0"; } int temp = (int.Parse(num)) + 1; return createFileName(sDir, sFExt, temp.ToString()); } return sDir + @"/" + sFExt + stemp + num + @".igs"; } //メッセージボックス static void Msgbox(string msg) { MessageBox.Show(msg, "メッセージ", MessageBoxButtons.OK, MessageBoxIcon.Error); } } //点 class Point3d { private double[] pos = new double[3];//0-X 1-Y 2-Z public bool Ok = true;//取得の成功 //設定 public void set(string txt, char split) { //列の確認 string[] temp = txt.Split(split);//0-X 1-Y 2-Z if (temp.Length < 3) { this.Ok = false; return; } //数値の確認 double d; for (int i = 0; i < 3; i++) { if (double.TryParse(temp[i], out d)) { pos[i] = d; } else { this.Ok = false; return; } } } //取得 public double X() { return this.pos[0]; } public double Y() { return this.pos[1]; } public double Z() { return this.pos[2]; } public string sX() { return this.pos[0].ToString(); } public string sY() { return this.pos[1].ToString(); } public string sZ() { return this.pos[2].ToString(); } } //Iges class Iges { private char _splitword = ','; //分割文字設定 xyzフォーマット対応 public void SetSplitWord(char word) { _splitword = word; } //エントリタイプから作成されるコード private struct sCode { public List<StringBuilder> P;//パラメータデータ public List<StringBuilder> D;//ディレクトリエントリ } //Igesのエクスポート public int expIges(string[] txts, string inFil, string exDir, string exFil) { string fname = exDir + "\\" + exFil;//何で@"/"じゃ駄目なのかな? var Scode = new List<string>();//スタートセクション var Gcode = new List<string>();//グローバルセクション var Pcode = new List<StringBuilder>();//パラメータデータセクション var Dcode = new List<StringBuilder>();//ディレクトリエントリセクション string Tcode;//ターミネートセクション Point3d pnt; //形状処理 sCode Recode; foreach (var txt in txts) { pnt = new Point3d(); pnt.set(txt, _splitword); if (pnt.Ok) { Recode = new sCode(); //116 int pointer116 = Dcode.Count + 1; t116(pnt, Pcode.Count + 1, Dcode.Count + 1, out Recode); Pcode.AddRange(Recode.P); Dcode.AddRange(Recode.D); } } //S Scode = substringAtCount("thx_Unofficial_CATIA_User_Forum".PadRight(72), 72); //G Gcode = global(inFil, exFil); //T Tcode = Termination(Scode.Count, Gcode.Count, Dcode.Count, Pcode.Count); System.Text.Encoding enc = System.Text.Encoding.GetEncoding("shift_jis"); string extxt = ""; var i = 1; foreach (var st in Scode) { extxt += st + "S" + (i.ToString()).PadLeft(7) + "\n"; i++; } System.IO.File.WriteAllText(fname, extxt, enc); i = 1; extxt = ""; foreach (var st in Gcode) { extxt += st + "G" + (i.ToString()).PadLeft(7) + "\n"; i++; } System.IO.File.AppendAllText(fname, extxt, enc); i = 1; extxt = ""; foreach (var st in Dcode) { extxt += st + "D" + (i.ToString()).PadLeft(7) + "\n"; i++; } System.IO.File.AppendAllText(fname, extxt, enc); i = 1; extxt = ""; foreach (var st in Pcode) { extxt += st + "P" + (i.ToString()).PadLeft(7) + "\n"; i++; } System.IO.File.AppendAllText(fname, extxt, enc); System.IO.File.AppendAllText(fname, Tcode.ToString(), enc); return Dcode.Count / 2;//点の数 } //ターミネートセクション private string Termination(int s, int g, int d, int p) { string temp = ""; temp += "S" + (s.ToString()).PadLeft(7); temp += "G" + (g.ToString()).PadLeft(7); temp += "D" + (d.ToString()).PadLeft(7); temp += "P" + (p.ToString()).PadLeft(7); temp = temp.PadRight(72) + "T 1"; return temp; } //グローバルセクション private List<string> global(string inFExt, string exFil) { var ver = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; string[] gform = new string[] { "1H,,", "1H;,", inFExt.Length.ToString() + "H" + inFExt + ",", exFil.Length.ToString() + "H" + exFil + ",", "7Hkantoku,", ("csv2igs"+ver.ToString()).Length.ToString()+"Hcsv2igs" + ver.ToString() + ",", "32,", "75,", "6,", "75,", "15,", inFExt.Length.ToString() + "H" + inFExt + ",", "1.0,", "2,", "2HMM,", "1000,", "1.0,", "15H" + DateTime.Now.ToString("yyyyMMdd.HHmmss") + ",", "0.001,", "10000.0,", "8Hhogehoge,", "8Hhogehoge,", "11,", "0,", "15H" + DateTime.Now.ToString("yyyyMMdd.HHmmss") + ",;" }; var temp = substringAtCount(string.Join("", gform), 72); temp[temp.Count - 1] = temp[temp.Count - 1].PadRight(72); return temp; } //エントリ116 private void t116(Point3d pnt, int Pcount, int Dcount, out sCode Re) { //パラメータ部 var templist = new List<string>(); templist.Add("116,"); templist.Add(D2F_str(pnt.X()) + ","); templist.Add(D2F_str(pnt.Y()) + ","); templist.Add(D2F_str(pnt.Z()) + ","); templist.Add("0,"); templist.Add("0,"); templist.Add("0;"); var Psect = new List<StringBuilder>(); split_pra(templist, Psect, 64);//複行化 //平面パラメータ部追記 for (int i = 0; i < Psect.Count; i++) { Psect[i].Append((Dcount.ToString()).PadLeft(8)); } //平面ディレクトリ部 var Dsect = new List<StringBuilder>(); string[] pldelform1 = new string[]//一行目 { "116",Pcount.ToString(),"0","0","1","0","0","0","00000001" }; var pldellist = new StringBuilder(); foreach (var pldel in pldelform1) { pldellist.Append(pldel.PadLeft(8)); } Dsect.Add(pldellist); string[] pldelform2 = new string[]//二行目 { "116","0","0",Psect.Count.ToString(),"0","","","","0" }; pldellist = new StringBuilder(); foreach (var pldel in pldelform2) { pldellist.Append(pldel.ToString().PadLeft(8)); } Dsect.Add(pldellist); Re.D = Dsect; Re.P = Psect; } //パラメータ部用複数行処理 private static void split_pra(List<string> templist, List<StringBuilder> Psect, int sLng) { var sb = new StringBuilder(); foreach (var pl in templist) { if (sb.Length + pl.Length > sLng) { var temp = new StringBuilder(); var st = sb.ToString().PadRight(sLng); temp.Append(st); Psect.Add(temp); sb = new StringBuilder(); } sb.Append(pl); if (pl.IndexOf(";") > -1) { var temp = new StringBuilder(); var st = sb.ToString().PadRight(sLng); temp.Append(st); Psect.Add(temp); } } } //doubleから下6桁で指数表記しないstringを返す private string D2F_str(double dub) { return (dub.ToString("0.######")); } //文字数による分割 private List<string> substringAtCount(string source, int count) { List<string> substList = new List<string>(); int length = (int)Math.Ceiling((double)source.Length / (double)count); for (int i = 0; i < length; i++) { int start = count * i; if (start >= source.Length) { break; } if (start + count > source.Length) { substList.Add(source.Substring(start)); } else { substList.Add(source.Substring(start, count)); } } return substList; } } }
ビルド済みファイルはこちらにUpしております。
https://grabcad.com/library/csvfile-inport-test-1
(利用には.NET Framework4.0以上が必要です)
CSV又はXYZフォーマットのファイルをD&Dすることで、Igesファイルを作成できます。
Igesであれば、CATIAに限らず利用できますし、大量の点を読み込む場合は
マクロで直接読み込むよりかなり高速です。
"USPRO" と言うサイトにIges5.3の仕様PDFがあったのですが、
サイトが消えているような・・。 仕様書自体はこちらにありました。
http://diyhpl.us/~bryan/papers2/IGES5-3_forDownload.pdf