こちらの続きです。
レイヤーの扱いを考える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呼び出しであれば、恐らくそこそこ
勝負にはなると思いますが・・・。