C#ATIA

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

レイヤーの扱いを考える6

こちらの続きです。
レイヤーの扱いを考える5 - C#ATIA


その後あちこち修正してしまったので、まとめてこちら。

//cs
namespace catLeyTest {
    using System.Linq;
    using System.Diagnostics;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;//COMオブジェクトを操作するために必要
    using INFITF;//Catiaのライブラリ
    using MECMOD;//Catiaのライブラリ
    using HybridShapeTypeLib;//Catiaのライブラリ

    static class Program {
        static void Main() {
            var catia = (INFITF.Application)Marshal
                        .GetActiveObject("CATIA.Application");
            var test = new LayerTest_CS(catia);

            Stopwatch sw = new Stopwatch();
            sw.Start();
            test.StartTest();
            sw.Stop();
            MessageBox.Show(string.Format("{0}秒", sw.Elapsed));
        }
    }

    class LayerTest_CS {
        public LayerTest_CS(INFITF.Application Catia) {
            CatExtension.State = new CatiaContainer(Catia);
        }

        public void StartTest() {
            CatExtension.HSOSynchronized(false);

            var hybridShapes = CatExtension.State.Part
                               .HybridBodies.Item(1)
                               .HybridShapes;

            foreach (var hsgp in Enumerable.Range(1, hybridShapes.Count)//①
                                    .Select(i => hybridShapes.Item(i))//②
                                    .GroupBy(i => i.GetLayer())//③
                                    .OrderBy(i => i.Key)) {//④
                hsgp.CreateHybridBody();
                hsgp.ToArray().Move();//⑤
            }
            CatExtension.HSOSynchronized(true);
        }
    }

    class CatiaContainer {
        private INFITF.Application catia;
        private PartDocument partDoc = null;
        private Part part = null;
        private Selection selection = null;
        private HybridShapeFactory hybridShapeFactory = null;
        private HybridBody hybridBody = null;

        public CatiaContainer(INFITF.Application cat) {
            Catia = cat;
            Setting();
        }

        ~CatiaContainer() {
            if (hybridBody != null) { Marshal.ReleaseComObject(hybridBody); }
            if (hybridShapeFactory != null) {
               Marshal.ReleaseComObject(hybridShapeFactory); }
            if (selection != null) { Marshal.ReleaseComObject(selection); }
            if (part != null) { Marshal.ReleaseComObject(part); }
            if (partDoc != null) { Marshal.ReleaseComObject(partDoc); }
            if (catia != null) { Marshal.ReleaseComObject(catia); }
        }

        public void Setting() {
            PartDoc = catia.ActiveDocument as PartDocument;
            Part = PartDoc.Part as Part;
            Selection = PartDoc.Selection as Selection;
            HybridShapeFactory = Part.HybridShapeFactory as HybridShapeFactory;
        }

        public INFITF.Application Catia {
            get {
                return catia;
            }
            private set {
                catia = value;
            }
        }
        public PartDocument PartDoc {
            get {
                return partDoc;
            }
            private set {
                partDoc = value;
            }
        }
        public Part Part {
            get {
                return part;
            }
            private set {
                part = value;
            }
        }
        public Selection Selection {
            get {
                return selection;
            }
            private set {
                selection = value;
            }
        }
        public HybridShapeFactory HybridShapeFactory {
            get {
                return hybridShapeFactory;
            }
            private set {
                hybridShapeFactory = value;
            }
        }
        public HybridBody HybridBody {
            get {
                return hybridBody;
            }
            set {
                hybridBody = value as HybridBody;
            }
        }
    }

    static class CatExtension {
        public static CatiaContainer State { get; set; }

        public static int GetLayer(this HybridShape hy) {
            State.Selection.Clear();
            State.Selection.Add(hy);
            CatVisLayerType Layertype;
            int Layer;
            State.Selection.VisProperties.GetLayer(out Layertype, out Layer);
            return Layer;
        }

        public static void CreateHybridBody(
            this IGrouping<int, HybridShape> gp) {
            CreateHybridBody(gp, (string.Format("Layer{0}", gp.Key)));
        }

        public static void CreateHybridBody(
            this IGrouping<int, HybridShape> gp, string name) {
            State.HybridBody = State.Part.HybridBodies.Add();
            State.HybridBody.set_Name(name);
        }

        public static void Move(this HybridShape[] hys) {
            State.Selection.Clear();
            Reference a = hys[1] as Reference;//⑥
            foreach (var hy in hys) {//⑦
                State.Selection.Add(hy);
            }
            State.Selection.Copy();
            State.Selection.Clear();
            State.Selection.Add(State.HybridBody);
            State.Selection.Paste();
            foreach (var hy in hys) {
                State.HybridShapeFactory.DeleteObjectForDatum(
                State.Part.CreateReferenceFromObject(hy));
            }
        }

        public static void HSOSynchronized(bool Switch) {
            State.Catia.HSOSynchronized = Switch;
        }
    }

CatiaContainerクラスとCatExtensionクラスは以前の物を拡張。
まだまだ修正の必要があります・・・。
(それ以上にExtensionと言うネーミングが不適格です)

①から④までは一行です。VBA

'vba
For Each Item In Collection
 :
Next

のCollection部分をLinqで作り上げています。

①②:CATIAのCollectionは、幾つか確認した限り
 C#でもForeachが使用できますが、Linqが使えません。
 列挙可能な状態にする為Enumerable.Range
 に突っ込んでいます。List<T>を利用する事も
 試したりしましたが、こちらの方が素直な感じがします。
③:前回同様の拡張メソッドでレイヤーを元にGroupByで
 グループ分けします。(実はこれが書きたかったんです)
④:グループ分けしたレイヤー番号毎にソートします。
 これらを元にforeachするので、レイヤーの種類分しか
 ループしません。
 これらをVBAで書くとなると、結構な手間な気がしています。

⑤:拡張メソッドでレイヤー分けされた要素を、各形状セットに
 移動します。

⑥:本来、オブジェクトからリファレンスを取得する際は、

'vba
Set oReference = oPart.CreateReferenceFromObject(hoge)

 の形にするのが正しいと思うのですが、オブジェクトを
 リファレンスクラスにキャストすると、かなり取得できる場合が
 多いです。(VBAでも)

VBAではSelection.Searchで同一レイヤーの要素を
 探しましたが、既に③のGroupByで同一レイヤーの要素は
 取得しているため、Selection.Searchを利用せずに
 Selectionに突っ込んでいます。

手元にあった客先支給のIgesデータを変換した、4MB弱程のもので、
実行結果を比較します。

VBA-ツールバー VBA-エディタ C#
1回目 4.81秒 10.37秒 10.24秒
2回目 4.66秒 10.48秒 10.21秒
3回目 4.66秒 10.33秒 10.23秒

さらに22MB程のもので、実行結果を比較です。

VBA-ツールバー VBA-エディタ C#
1回目 33.04秒 174.37秒 187.24秒
2回目 33.12秒 173.18秒 185.91秒

えぇわかってます、C#だと遅い事を・・・。
DLL化してVBA呼び出しであれば、恐らくそこそこ
勝負にはなると思いますが・・・。