0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Autodesk Inventor API Hacking (SketchEntityがActivatedObject内かどうか)

Posted at

#0. はじめに
Freeradicalの中の人、yamarahです。
InteractionEventsなどを使ってSketch要素を操作する場合は、対象のSketchEntityが編集中の(Activeな)Sketchに含まれるのか、はたまた他のSketchの要素なのかを判断したくなるでしょう。
SketchEntity.Parent == ActiveDocument.ActivatedObjectで良いんじゃない?」と思うかもしれませんが、そう簡単にはいかないのです。

#1. 考慮すべき条件分け
Sketch編集中と言っても、実は色々な状況があります。すぐに思いつくのは、アセンブリ環境でパーツをInPlace編集している場合です。
同じパーツのオカレンスが他にもある可能性があるので、アセンブリ環境ではProxyに対して比較/操作する必要があります。
次に、忘れがちなのが、Sketchブロックです。Sketchブロック編集には2種類あって、通常のSketch編集中にInPlaceでブロック編集する方法と、モデルツリー内のブロックフォルダーから編集する場合です。

ですので、

  • 2パターン (アセンブリでのInPlace編集かどうか)
  • 3パターン (通常のSketch編集 / 通常のSketch中のInPlaceブロック編集 / ブロックのみを編集)

の掛け合わせで、計6パターンの状況があります。

#2. ブロックについて
SketchBlockは、Sketchにおけるブロックの実体です。
SketchBlockDefinitionは、SketchBlockの雛形です。
Assembly/Partの関係に例えると、次のようになります。

AssemblyとPartの関係 SketchとSketchBlockの関係
AssemblyDocument PlanarSketch (*1)
ComponentOccurrence SketchBlock
PartDocument SketchBlockDefinition
(*1) SketchBlockを内包する親SketchBlockDefinitionの可能性もある

なお、SketchBlockDefinitionPlanarSketchを継承していますので、状況によってはSketchBlockDefinitionPlanarSketchと扱って処理できます。

#3. ActivatedObjectに入っているもの
次に、ActiveEditDocument.ActivatedObjectに入っているものを確認しておきましょう。

状況 ActivatedObject
通常のSketch編集 PlanarSketch
Sketch編集中にBlockをInPlace編集 SketchBlock
Blockのみを編集 SketchBlockDefinition
なんとなく、2番目の処理がやっかいそうなのが分かります。

#4. 実際のコード
まずは、ActivatedObjectを可能性のある各形式に変換します。

// PartDocument編集中を確認。
if (!(InventorApplication.ActiveEditDocument is PartDocument partDoc)) return;

// ActivatedObjectを、PlanarSketch, SketchBlockDefinition, SketchBlockに変換してみる。
var activeSketch = partDoc.ActivatedObject as PlanarSketch; // 普通のSketch編集中と、InPlaceではないBlock編集中時に非null
var activeBlockDef = partDoc.ActivatedObject as SketchBlockDefinition;    // InPlaceではないBlock編集中時に非null
var activeBlock = partDoc.ActivatedObject as SketchBlock;   // InPlaceでBlock編集中に非null

先に述べた通り、SketchBlockDefinitionPlanarSketchに変換可能なので注意してください。
次に、SketchBlockが取得できた場合は、そこからactiveSketchactiveBlockDefを取得します。

// InPlaceでBlock編集中時は、activeBlockからactiveSketchとblockDefを取得する。
if (activeBlock != null)
{
    activeBlockDef = activeBlock.Definition;
    activeSketch = activeBlockDef as PlanarSketch;
}

この時点ではactiveSketch == nullの可能性があるので、それをはじきます。

// activeSketchがnullの場合は中止。例えば、ActivatedObjectがSketch3Dだった場合とか。
if (activeSketch == null) return;

次に、アセンブリ環境中にパーツをInPlace編集している場合を考慮します。その場合は、各ObjectをActiveOccurrence経由のproxyに差し替えます。

// Assembly環境で、PartDocumentをInPlace編集している可能性を考慮する。
ComponentOccurrence? activeOccurrence = null;
if (partDoc != InventorApplication.ActiveDocument)
{
    // InPlace編集中だった場合
    var topAssyDoc = InventorApplication.ActiveDocument as AssemblyDocument;
    if (topAssyDoc == null) return; // あり得ないはずだが、念のため

    // activeSketchをSketchProxyに変換する。
    object proxy;
    activeOccurrence = topAssyDoc.ComponentDefinition.ActiveOccurrence;
    activeOccurrence.CreateGeometryProxy(activeSketch, out proxy);
    activeSketch = (PlanarSketch)proxy;

    // blockDefが非nullの場合は、activeBlockDef == activeSketchなので、同じproxy値を設定する。
    if (activeBlockDef != null)
    {
        activeBlockDef = (SketchBlockDefinition)proxy;
    }

    // activeBlockが設定されている場合は、同様にSketchBlockProxyに変換する。
    if (activeBlock != null)
    {
        activeOccurrence.CreateGeometryProxy(activeBlock, out proxy);
        activeBlock = (SketchBlock)proxy;
    }
}

Proxyに差し替えたので、以後はAssembly中かどうか気にしなくて良いです。
残りの条件分け、Blockがらみの条件を抽出します。

// SketchBlockを編集中かどうか
bool inSketchBlockEdit = activeBlockDef != null;
// Sketch編集中に、SketchBlockをInPlace編集中かどうか
bool inInplaceSketchBlockEdit = activeBlock != null;

// Debug
System.Diagnostics.Debug.WriteLine($"{nameof(inSketchBlockEdit)} : {inSketchBlockEdit}");
System.Diagnostics.Debug.WriteLine($"{nameof(inInplaceSketchBlockEdit)} : {inInplaceSketchBlockEdit}");

ここまでが下準備です。毎回評価する必要はないので、OnExecuteなりOnNewEditObjectで更新すると良いでしょう。

では、実際にSketchEntityActivatedObjectに含まれるか検証しましょう。
実験用のSketchEntityの供給元として、毎度おなじみのSelectSetを使います。

// SelectSetから要素を1つ取る。
var selectSet = InventorApplication.ActiveDocument.SelectSet;   // ActiveEditDocumentではないことに注意
if (selectSet.Count == 0) return;
if (!(selectSet[1] is SketchEntity entity)) return; // Indexは1から始まる

やっと実際の確認部分です。

// entityが、ActivatedObjectの直接の要素かどうか。
bool isDirectChildOfActivatedObject = false;

if (inInplaceSketchBlockEdit)
{
    // Sketch環境でBlockをInPlace編集中は、entityの親が編集中のBlockかどうかで確認する。
    if (activeBlock == entity.ContainingSketchBlock)
    {
        isDirectChildOfActivatedObject = true;
    }
}
else
{
    // それ以外(通常のSketch編集、Blockのみを編集)の場合は、entityの親がactiveSketchかどうかで判断する。
    if (entity.Parent == activeSketch)
    {
        isDirectChildOfActivatedObject = true;
    }
}

// Debug
System.Diagnostics.Debug.WriteLine($"{nameof(isDirectChildOfActivatedObject)} : {isDirectChildOfActivatedObject}");

ここで、isDirectChildOfActivatedObjectの意味ですが、名前の通り、ActivatedObjectに直接所有されている(ユーザーに操作可能に見える)かどうかです。
例えば、通常のSketch編集中に、そのSketchに含まれているBlock内の各要素は、Sketch(== ActivatedObject)に内包されていると言えます。しかし、ここで判断したいのは、その要素がActivatedObjectの直接の子要素かどうかなので、Block経由の場合はfalseになって欲しいわけです。

最後に、おまけです。アセンブリ環境でパーツをInPlace編集中に、あるSketchEntityがInPlace編集中のOccurrenceに含まれるかどうかを確認します。
このコードは動作確認していないのですが、問題ないと思います。

// ActiveOccurrenceに含まれるかどうか
bool inActiveOccurrence = false;
if (activeOccurrence == null)
{
    // アセンブリ中の編集でなければ、常にtrue
    inActiveOccurrence = true;
}
else
{
    var containingSketchProxy = entity.Parent as PlanarSketchProxy;
    if (containingSketchProxy?.ContainingOccurrence == activeOccurrence)
    {
        inActiveOccurrence = true;
    }
}

// Debug
System.Diagnostics.Debug.WriteLine($"{nameof(inActiveOccurrence)} : {inActiveOccurrence}");

以上です。

#5. まとめ
繰り返しになりますが、上記コードを1つにまとめたものを貼っておきます。

// PartDocument編集中を確認。
if (!(InventorApplication.ActiveEditDocument is PartDocument partDoc)) return;

// ActivatedObjectを、PlanarSketch, SketchBlockDefinition, SketchBlockに変換してみる。
var activeSketch = partDoc.ActivatedObject as PlanarSketch; // 普通のSketch編集中と、InPlaceではないBlock編集中時に非null
var activeBlockDef = partDoc.ActivatedObject as SketchBlockDefinition;    // InPlaceではないBlock編集中時に非null
var activeBlock = partDoc.ActivatedObject as SketchBlock;   // InPlaceでBlock編集中に非null

// InPlaceでBlock編集中時は、activeBlockからactiveSketchとblockDefを取得する。
if (activeBlock != null)
{
    activeBlockDef = activeBlock.Definition;
    activeSketch = activeBlockDef as PlanarSketch;
}

// activeSketchがnullの場合は中止。例えば、ActivatedObjectがSketch3Dだった場合とか。
if (activeSketch == null) return;

// Assembly環境で、PartDocumentをInPlace編集している可能性を考慮する。
ComponentOccurrence? activeOccurrence = null;
if (partDoc != InventorApplication.ActiveDocument)
{
    // InPlace編集中だった場合
    var topAssyDoc = InventorApplication.ActiveDocument as AssemblyDocument;
    if (topAssyDoc == null) return; // あり得ないはずだが、念のため

    // activeSketchをSketchProxyに変換する。
    object proxy;
    activeOccurrence = topAssyDoc.ComponentDefinition.ActiveOccurrence;
    activeOccurrence.CreateGeometryProxy(activeSketch, out proxy);
    activeSketch = (PlanarSketch)proxy;

    // blockDefが非nullの場合は、activeBlockDef == activeSketchなので、同じproxy値を設定する。
    if (activeBlockDef != null)
    {
        activeBlockDef = (SketchBlockDefinition)proxy;
    }

    // activeBlockが設定されている場合は、同様にSketchBlockProxyに変換する。
    if (activeBlock != null)
    {
        activeOccurrence.CreateGeometryProxy(activeBlock, out proxy);
        activeBlock = (SketchBlock)proxy;
    }
}

// SketchBlockを編集中かどうか
bool inSketchBlockEdit = activeBlockDef != null;
// Sketch編集中に、SketchBlockをInPlace編集中かどうか
bool inInplaceSketchBlockEdit = activeBlock != null;

// Debug
System.Diagnostics.Debug.WriteLine($"{nameof(inSketchBlockEdit)} : {inSketchBlockEdit}");
System.Diagnostics.Debug.WriteLine($"{nameof(inInplaceSketchBlockEdit)} : {inInplaceSketchBlockEdit}");

// SelectSetから要素を1つ取る。
var selectSet = InventorApplication.ActiveDocument.SelectSet;   // ActiveEditDocumentではないことに注意
if (selectSet.Count == 0) return;
if (!(selectSet[1] is SketchEntity entity)) return; // Indexは1から始まる

// entityが、ActivatedObjectの直接の要素かどうか。
bool isDirectChildOfActivatedObject = false;

if (inInplaceSketchBlockEdit)
{
    // Sketch環境でBlockをInPlace編集中は、entityの親が編集中のBlockかどうかで確認する。
    if (activeBlock == entity.ContainingSketchBlock)
    {
        isDirectChildOfActivatedObject = true;
    }
}
else
{
    // それ以外(通常のSketch編集、Blockのみを編集)の場合は、entityの親がactiveSketchかどうかで判断する。
    if (entity.Parent == activeSketch)
    {
        isDirectChildOfActivatedObject = true;
    }
}

// Debug
System.Diagnostics.Debug.WriteLine($"{nameof(isDirectChildOfActivatedObject)} : {isDirectChildOfActivatedObject}");

// ActiveOccurrenceに含まれるかどうか
bool inActiveOccurrence = false;
if (activeOccurrence == null)
{
    // アセンブリ中の編集でなければ、常にtrue
    inActiveOccurrence = true;
}
else
{
    var containingSketchProxy = entity.Parent as PlanarSketchProxy;
    if (containingSketchProxy?.ContainingOccurrence == activeOccurrence)
    {
        inActiveOccurrence = true;
    }
}

// Debug
System.Diagnostics.Debug.WriteLine($"{nameof(inActiveOccurrence)} : {inActiveOccurrence}");

#99. 親の記事に戻る
Autodesk Inventor API Hacking (概略)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?