C#ATIA

↑タイトル詐欺 主にFusion360API 偶にCATIA V5 VBA(絶賛ネタ切れ中)

外部ファイルから点を3Dに取り込む3

こちらの続きです。
外部ファイルから点を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