<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>python | じじぃの引出し</title>
	<atom:link href="https://www.kazuban.com/blog/category/python/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.kazuban.com/blog</link>
	<description>なにかしら、皆さんの参考になれば幸いです！</description>
	<lastBuildDate>Thu, 22 Oct 2026 00:33:04 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://www.kazuban.com/blog/wp-content/uploads/2020/05/cropped-ICON-1-32x32.png</url>
	<title>python | じじぃの引出し</title>
	<link>https://www.kazuban.com/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Gコード分析ライブラリ for Python・Ncコメント編【Vol.2】</title>
		<link>https://www.kazuban.com/blog/ncdata-library-nc-comment/</link>
					<comments>https://www.kazuban.com/blog/ncdata-library-nc-comment/#respond</comments>
		
		<dc:creator><![CDATA[kazuban]]></dc:creator>
		<pubDate>Wed, 21 Oct 2026 20:01:00 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[NC]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Claude、ＮＣデータ、Python、バイブコーディング]]></category>
		<guid isPermaLink="false">https://www.kazuban.com/blog/?p=13107</guid>

					<description><![CDATA[Ncコメント編【Vol.2】 前回は、「NCワード」を「アドレスと数値・数字」に分解するコードを作成しました次は、一行の「NCブロック」を「NCワード」に分解させる予定ですが、その前に処理しておきたいのがコメントです。コ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading has-text-align-center">Ncコメント編【Vol.2】</h1>



<p class="wp-block-paragraph">前回は、「NCワード」を「アドレスと数値・数字」に分解するコードを作成しました<br>次は、一行の「NCブロック」を「NCワード」に分解させる予定ですが、その前に処理しておきたいのがコメントです。<br>コメントはファナックでは、（　～　）に挟まれた文字は、制御器は無視するのでメッセージなどに利用されますが、<br>「Gコード」や「X、Y、Z」などNCワードと同形式の文字列がコメント部に含まれていると<br>単純に文字列検索だけで処理すると、思わぬ分析ミスになりかねません<br>この記事では、純粋なコード部分とコメント部分を分離するライブラリを作成します</p>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">コントローラによるコメント記号の種類</a></li><li><a href="#toc2" tabindex="0">クラスライブラリ</a></li><li><a href="#toc3" tabindex="0">NCコメントプロセッサクラス</a></li><li><a href="#toc4" tabindex="0">NC分析ライブラリ、記事一覧</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">コントローラによるコメント記号の種類</span></h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Fanuc制御器では ( で始まり、 ) で閉じるまでをコメントと認識<br>このコメントは、<span class="marker-under">複数行を跨いでも</span> ) で閉じるまで、コメントとして扱います</p>
</blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">OSP制御器も基本的にFanucと同じですが、<span class="marker-under">( から、行末まで</span>をコメントにします<br>したがって、 ) で閉じる必要はないですが、Fanucのように、行を跨がせないのが一般的です<br>変換ソフトなどで、ファナックと共有したい場合には、確実に閉じたほうが安全です</p>
</blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Heidenhain の場合は、<span class="marker-under">; 文字から、行末まで</span>、<br><span class="marker-under">行頭に　* の場合一行すべてをコメント</span>として扱います</p>
</blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Roedersの場合には、C言語に似ていて、<br><span class="marker-under">/* ～ */の間</span>、や　<span class="marker-under">// 文字列から行末まで</span>がコメントになります</p>
</blockquote>



<p class="wp-block-paragraph">今回は、将来性も考えて、上記４点に対応した、コメント処理ライブラリを作成します</p>



<h2 class="wp-block-heading"><span id="toc2">クラスライブラリ</span></h2>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue">　<span class="fz-14px"><span class="fz-18px"><span class="fz-20px">class BlockCommentRule:</span></span></span>　</span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph">「開始記号〜終了記号」で囲むタイプのコメント1種類分の仕様を定義<br>行コメント（&#8221;;&#8221; や &#8220;//&#8221;）はこのクラスの対象外（line_markers側で扱う）</p>



<p class="wp-block-paragraph">open_: 開始記号。例 &#8220;(&#8221; &#8220;/*&#8221;<br>close_: 終了記号。例 &#8220;)&#8221; &#8220;*/&#8221;<br>nested: 入れ子 &#8220;(&#8230;(&#8230;)&#8230;)&#8221; を許容するか。<br>multiline: 行末までに閉じなかった場合、未閉鎖の状態を次の行に持ち越すか<br>　　True &nbsp;= 複数行にまたがるコメントを許容する（例: FANUC）<br>　　False = 必ずその行の中で強制的に閉じる（例: OSPは自動で閉じるがデータでの処理が安全）</p>



<pre class="wp-block-preformatted has-black-color has-watery-red-background-color has-text-color has-background"># test code<br>bcr = BlockCommentRule("/*", "*/")<br>open = bcr.open<br>close = bcr.close<br>print(f"コメント始まり文字={open} コメント終了文字={close}")</pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"> /* */</p>
</blockquote>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue">　<span class="fz-14px"><span class="fz-18px"><span class="fz-20px">class DialectSpec(TypedDict):</span></span></span>　</span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph"><code>TypedDict</code> は 実態はただの辞書（dict）であるが、dictに型情報を付与するための仕組み。<br>dictは値の型が曖昧だが、このクラスで辞書の型を決定し型情報が違う場合、<br>静的型チェッカーが教えてくれる。</p>



<pre class="wp-block-preformatted has-black-color has-watery-red-background-color has-text-color has-background">#このクラスでコメントのタイプの型形式を定義
class DialectSpec(TypedDict):
&nbsp; &nbsp; blocks: List[BlockCommentRule] # 囲むタイプ [("(",")") , ("/*","*/")]など
&nbsp; &nbsp; line_markers: List[str]        # 行末までのタイプ [ ";" , "//" ]など
&nbsp; &nbsp; line_start_markers: List[str]  # 必ず先頭にあるタイプ["*"]など</pre>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue">　<span class="fz-14px"><span class="fz-18px"><span class="fz-20px">DIALECTS: Dict[str, DialectSpec]</span></span></span>　</span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph">制御器名とコメント記法（囲みコメントか単独か）の違いをまとめて定義<br>DIALECTS[&#8220;fanuc&#8221;][&#8220;blocks&#8221;][0].open で、<br>&#8220;fanuc&#8221;の&#8221;blicks&#8221;コメントの始まり文字(open)を参照できる</p>



<pre class="wp-block-preformatted has-black-color has-watery-red-background-color has-text-color has-background"># test code
a = DIALECTS["osp"]["blocks"][0].open
b = DIALECTS["osp"]["blocks"][0].close
c = DIALECTS["osp"]["blocks"][0].nested
d = DIALECTS["osp"]["blocks"][0].multiline
print(f"open={a} close={b} nested={c} multiline={d}") </pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">「実行結果」<br>open=( close=) nested=True multiline=False</p>
</blockquote>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue">　<span class="fz-14px"><span class="fz-18px"><span class="fz-20px">class NcCommentProcessor:</span></span></span>　</span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph">NCブロックを純粋コードとコメントに分解する</p>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue"><span class="marker">　<span class="fz-14px"><span class="fz-18px"><span class="fz-20px"><span class="fz-16px">def  _init__</span></span></span></span></span></span></strong><span class="marker">(self, dialect: Union[str, Sequence[str]] = &#8220;fanuc&#8221;):</span><strong><span class="marker-blue"><span class="marker">　</span></span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph">引数：dialectに制御器情報を渡すが、複数定義にも対応している<br> dialect=&#8221;fanuc&#8221;（文字列1個）と dialect=[&#8220;fanuc&#8221;,&#8221;heidenhain&#8221;]（リスト）の両方に対応<br>また、省略定義にも対応<br>&#8220;F&#8221;→&#8221;fanuc&#8221;  &#8220;O&#8221;→&#8221;osp&#8221;  &#8220;H&#8221;→&#8221;heidenhain&#8221;  &#8220;R&#8221;→&#8221;roeders&#8221; </p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue"><span class="marker">　</span></span></strong><span class="marker"> @property</span><br>    <span class="marker">def  open_comment(self) -> str:</span><strong><span class="marker-blue"><span class="marker">　</span></span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph">コメントの始まり記号を返す（@propertyなので、変数のように使える)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue"><span class="marker">　</span></span></strong><span class="marker">def reset(self) -> None:</span><strong><span class="marker-blue"><span class="marker">　</span></span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph">コメントの引き継ぎ状態をリセットする</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue"><span class="marker">　</span></span></strong><span class="marker">def  _scan(self, line: str)-> List[Tuple[str, str]]:</span><strong><span class="marker-blue"><span class="marker">　</span></span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph">一行のNC文字列を、NCコードとコメントに分解する</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue"><span class="marker">　</span></span></strong><span class="marker">reset_open_block(self):</span><strong><span class="marker-blue"><span class="marker">　</span></span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph">別のNCデータを連続で実施する場合、コメントを確実に閉じる</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box not-nested-style cocoon-block-label-box"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text"><strong><span class="marker-blue"><span class="marker">　</span></span></strong><span class="marker">def  parse_code_comment(self, line: str)-> Tuple[str, str]:</span><strong><span class="marker-blue"><span class="marker">　</span></span></strong></span></div><div class="label-box-content block-box-content box-content">
<p class="wp-block-paragraph">一行NC文字列をNCコードとコメントに分解し、それぞれtupleで返す</p>
</div></div>



<pre class="wp-block-preformatted has-black-color has-watery-red-background-color has-text-color has-background"># test code<br>ncblock = [<br>    "G01 X10 Y20 (this is a comment) F100(next",<br>    "next)G02 X30(unterminated comment ;starts here",<br>]<br>processor = NcCommentProcessor(dialect="fanuc")<br><br>for line in ncblock:<br>    print(f"Original Nc={line!r}")<br>    code, comment = processor.parse_code_comment(line)<br>    print(f"parse_code_comment: code={code!r}, comment={comment!r}")<br>    print(f"-------------------------------")</pre>



<pre class="wp-block-preformatted">「実行結果」<br>Original Nc='G01 X10 Y20 (this is a comment) F100(next'<br>parse_code_comment: code='G01 X10 Y20  F100', comment='(this is a comment)(next)'<br>-------------------------------<br>Original Nc='next)G02 X30(unterminated comment ;starts here'<br>parse_code_comment: code='G02 X30', comment='(next)(unterminated comment ;starts here)'<br>-------------------------------</pre>



<p class="wp-block-paragraph"></p>
</div></div>



<h2 class="wp-block-heading"><span id="toc3">NCコメントプロセッサクラス</span></h2>



<p class="wp-block-paragraph">実際の、コードです<br>ただし、コメント行が跨る場合で、意図しない分割になる可能性もあります<br>NCのコメントは、確実にその行で閉じる処理をすることが安全です</p>



<pre class="wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-1"><code>from typing import Dict, List, Optional, Sequence, Tuple, TypedDict, Union


class BlockCommentRule:
    """
    「開始記号〜終了記号」で囲むタイプのコメント1種類分の仕様。
    例: FANUCの "(" ")" や Roedersの "/*" "*/" など、開始と終了のペアで
    構成されるコメント記法を表す。開始記号だけ・終了記号だけの
    行コメント（";" や "//"）はこのクラスの対象外（line_markers側で扱う）。
    """

    __slots__ = ("open", "close", "nested", "multiline")
    """ __slots__ を書くと、このクラスのインスタンスは
    「ここに列挙した名前の属性しか持てない」という制限がかかる"""

    def __init__(
        self, open_: str, close_: str, nested: bool = False, multiline: bool = False
    ):
        """
        Args:
            open_: 開始記号。例 "(" "/*"
            close_: 終了記号。例 ")" "*/"
            nested: 入れ子 "(...(...)...)" を許容するか。
                True なら開始記号が現れるたびにネスト深さを1つ増やし、
                対応する終了記号がすべて出そろうまで閉じたとみなさない。
            multiline: 行末までに閉じなかった場合、未閉鎖の状態を
                次の行に持ち越すか。
                True  = 複数行にまたがるコメントを許容する（例: FANUC）
                False = 必ずその行の中で強制的に閉じる（例: OSP）
        """
        self.open = open_
        self.close = close_
        self.nested = nested  # 入れ子 "(...(...)...)" を許容するか
        self.multiline = multiline  # 閉じないまま行末を迎えたとき、次行に持ち越すか


class DialectSpec(TypedDict):
    """
    1つの制御装置（機種）が持つコメント記法一式を表す型。
    DIALECTS 辞書の値の型として使う。全dialectで3つのキーを
    必ず揃えること（使わないものは空リスト &#91;] を入れる）。
    """

    blocks: List&#91;BlockCommentRule]
    """開始〜終了で囲むタイプのコメント規則の一覧。例: &#91;("(",")"), ("/*","*/")]"""

    line_markers: List&#91;str]
    """行の"どこにあっても"、そこから行末まで丸ごとコメントになる記号。例: ";" "//" """

    line_start_markers: List&#91;str]
    """行の"先頭にある場合のみ"、そこから行末まで丸ごとコメントになる記号。
    例: HEIDENHAINの "*"（行の途中では掛け算として使われるため区別が必要）"""


# 機種(dialect)ごとのコメント記法定義
# ※ キー構成(blocks / line_markers / line_start_markers)は全エントリで必ず揃える
#   （使わないものは空リストを明示する）。バラバラだと型チェッカーが辞書の形を
#   一つに決められず、DIALECTS&#91;name]&#91;"..."] のようなアクセスで警告が出る。
DIALECTS: Dict&#91;str, DialectSpec] = {
    # FANUC: ( ) 入れ子OK、複数行にまたがる未閉鎖を許容
    "fanuc": {
        "blocks": &#91;BlockCommentRule("(", ")", nested=True, multiline=True)],
        "line_markers": &#91;],
        "line_start_markers": &#91;],
    },
    # OSP: ( ) 入れ子OK、ただし必ず1行内で強制的に閉じる
    #　通常は複数行にはまたがらないが、fanucとの互換性のため、multiline=Trueにする
    "osp": {
        "blocks": &#91;BlockCommentRule("(", ")", nested=True, multiline=True)],
        "line_markers": &#91;],
        "line_start_markers": &#91;],
    },
    # HEIDENHAIN: ; はどこにあっても行末までコメント。
    # * は「掛け算」としても使われるため、行頭にある場合のみ
    # アウトライン的な見出しコメントとして扱う（行の途中の * はコード）。
    "heidenhain": {
        "blocks": &#91;],
        "line_markers": &#91;";"],
        "line_start_markers": &#91;"*"],
    },
    # Roeders(独自制御言語): /* */ の囲み(複数行可) または // で行末までコメント
    # ※ 囲みコメント内での単文字コメント(; など)の扱いは未確認のため、
    #    ひとまず「囲み内は閉じタグ(*/)まで不透明」という一般的な仕様を仮定しています。
    #    要調査・要確認ポイント。
    "roeders": {
        "blocks": &#91;BlockCommentRule("/*", "*/", nested=False, multiline=True)],
        "line_markers": &#91;"//"],
        "line_start_markers": &#91;],
    },
}


class NcCommentProcessor:
    """
    NCブロックを純粋コードとコメントに分解する（機種ごとのコメント記法に対応）

    processor = NcCommentProcessor(dialect="fanuc")
    for line in ncs:
        code, comment = processor.parse_code_comment(line)
        print(f"code={code},comment={comment}")

    dialect:
        "F" or "fanuc"      : ( ) 入れ子OK、複数行にまたがる未閉鎖を許容
        "O" or "osp"        : ( ) 入れ子OK、必ず1行内で強制的に閉じる（次行に持ち越さない）
        "H" or "heidenhain" : ; はどこでも行末までコメント。* は行頭にある場合のみ行末までコメント
        "R" or "roeders"    : /* */ の囲み(複数行可) または // で行末までコメント

    複数dialectをまとめて使いたい場合はリストで渡す（ルールを合成する）:
        NcCommentProcessor(dialect=&#91;"fanuc", "heidenhain", "roeders"])
    リスト内で同じ開始記号（例: "(" ）を複数dialectが定義していた場合は、
    リストで先に書いたdialectのルールが優先される。
    """

    def __init__(self, dialect: Union&#91;str, Sequence&#91;str]] = "fanuc"):
        # isinstance:指定したデータ型（クラス）であるかどうか
        names = &#91;dialect] if isinstance(dialect, str) else list(dialect)
        mapping = {"F": "fanuc", "O": "osp", "H": "heidenhain", "R": "roeders"}
        for n, i in enumerate(names, 0):
            names&#91;n] = mapping.get(i, i)

        unknown = &#91;d for d in names if d not in DIALECTS]
        if unknown:
            raise ValueError(
                f"未知のdialectです: {unknown!r} (選べるのは {list(DIALECTS)})"
            )
        self.dialect = names&#91;0] if len(names) == 1 else names

        # 複数dialect分のルールを合成する。開始記号(open)が重複するものは
        # 先に書いたdialectのルールを優先し、後発の重複ルールは捨てる。
        blocks: List&#91;BlockCommentRule] = &#91;]
        seen_open = set()
        for name in names:
            for rule in DIALECTS&#91;name]&#91;"blocks"]:
                if rule.open in seen_open:
                    continue
                seen_open.add(rule.open)
                blocks.append(rule)

        line_markers: List&#91;str] = &#91;]
        for name in names:
            for marker in DIALECTS&#91;name]&#91;"line_markers"]:
                if marker not in line_markers:
                    line_markers.append(marker)
        # 長いマーカーを先に判定できるよう、長さ降順に並べる
        # （例: "/*" と "*" が両方あるとき、"*" だけで先に食われないように）
        line_markers.sort(key=len, reverse=True)

        line_start_markers: List&#91;str] = &#91;]
        for name in names:
            for marker in DIALECTS&#91;name].get("line_start_markers", &#91;]):
            #for marker in DIALECTS&#91;name]&#91;"line_start_markers"]:
                if marker not in line_start_markers:
                    line_start_markers.append(marker)
        line_start_markers.sort(key=len, reverse=True)

        self._blocks: List&#91;BlockCommentRule] = blocks
        self._line_markers: List&#91;str] = line_markers
        self._line_start_markers: List&#91;str] = line_start_markers
        # 行をまたぐ未閉鎖ブロックの状態: (rule, 現在の未閉鎖の深さ)
        self._open_block: Optional&#91;Tuple&#91;BlockCommentRule, int]] = None

    @property
    def open_comment(self) -> str:
        return self._open_block&#91;0].open if self._open_block else ""

    def reset(self) -> None:
        self._open_block = None

    def _scan(self, line: str) -> List&#91;Tuple&#91;str, str]]:
        """1行を (種別, 文字列) のトークン列に分解する。種別は 'code' か 'comment'。"""
        text = line.rstrip()
        n = len(text)
        tokens: List&#91;Tuple&#91;str, str]] = &#91;]
        i = 0

        # 前の行から続く未閉鎖ブロックコメントの続きを最優先で処理する
        # （ここを最初に処理することで、囲みの中の ; や // を誤って行コメント開始と
        #   判定してしまう不具合を避けている）
        if self._open_block is not None:
            rule, depth = self._open_block
            j = 0
            while j &lt; n and depth > 0:
                if rule.nested and text.startswith(rule.open, j):
                    depth += 1
                    j += len(rule.open)
                    continue
                if text.startswith(rule.close, j):
                    depth -= 1
                    j += len(rule.close)
                    continue
                j += 1
            if depth > 0:
                # まだ閉じない: 開始記号を補って「継続中のコメント」と分かるようにし、
                # 残っている深さ(depth)を次行にそのまま引き継ぐ
                tokens.append(("comment", rule.open + text + rule.close * depth))
                self._open_block = (rule, depth)
                return tokens
            tokens.append(("comment", rule.open + text&#91;:j]))
            self._open_block = None
            i = j

        while i &lt; n:
            matched = False

            # 行頭専用のマーカー（例: HEIDENHAINの見出し的な "*"）は
            # 行の一番最初の位置でのみコメット開始とみなす
            if i == 0:
                for marker in self._line_start_markers:
                    if text.startswith(marker, i):
                        tokens.append(("comment", text&#91;i:n]))
                        i = n
                        matched = True
                        break
                if matched:
                    continue

            for rule in self._blocks:
                if text.startswith(rule.open, i):
                    depth = 1
                    j = i + len(rule.open)
                    while j &lt; n and depth > 0:
                        if rule.nested and text.startswith(rule.open, j):
                            depth += 1
                            j += len(rule.open)
                            continue
                        if text.startswith(rule.close, j):
                            depth -= 1
                            j += len(rule.close)
                            continue
                        j += 1
                    if depth > 0:
                        tokens.append(("comment", text&#91;i:n] + rule.close * depth))
                        if rule.multiline:
                            self._open_block = (rule, depth)
                        i = n
                    else:
                        tokens.append(("comment", text&#91;i:j]))
                        i = j
                    matched = True
                    break

            if matched:
                continue

            for marker in self._line_markers:
                if text.startswith(marker, i):
                    tokens.append(("comment", text&#91;i:n]))
                    i = n
                    matched = True
                    break

            if matched:
                continue

            if tokens and tokens&#91;-1]&#91;0] == "code":
                tokens&#91;-1] = ("code", tokens&#91;-1]&#91;1] + text&#91;i])
            else:
                tokens.append(("code", text&#91;i]))
            i += 1

        return tokens


    def reset_open_block(self):
        """別のNCデータを連続で実施する場合、コメントを確実に閉じる"""
        block = self._open_block
        if block is not None:
            self.reset()

    def parse_code_comment(self, line: str) -> Tuple&#91;str, str]:
        """純粋コードとコメントを分割する"""
        tokens = self._scan(line)
        code = "".join(t for k, t in tokens if k == "code").rstrip()
        comment = "".join(t for k, t in tokens if k == "comment")
        return code, comment


# test code
if __name__ == "__main__":
    ncblock = &#91;
        "G01 X10 Y20 (this is a comment) F100(next",
        "next)G02 X30(unterminated comment ;starts here",
    ]
    processor = NcCommentProcessor(dialect="fanuc")

    for line in ncblock:
        print(f"Original Nc={line!r}")
        # code = processor.normalize(line)
        # print(f"normalize: line={code!r}")
        code, comment = processor.parse_code_comment(line)
        print(f"parse_code_comment: code={code!r}, comment={comment!r}")
        print(f"-------------------------------")
    processor.reset_open_block()
    for line in ncblock:
        print(f"Original Nc={line!r}")
        # code = processor.normalize(line)
        # print(f"normalize: line={code!r}")
        code, comment = processor.parse_code_comment(line)
        print(f"parse_code_comment: code={code!r}, comment={comment!r}")
        print(f"-------------------------------")
</code></pre>



<h2 class="wp-block-heading"><span id="toc4">NC分析ライブラリ、記事一覧</span></h2>



<div class="wp-block-columns has-watery-red-background-color has-background is-style-bottom-margin-1em has-bottom-margin is-layout-flex wp-container-core-columns-is-layout-cb1de518 wp-block-columns-is-layout-flex" style="border-style:none;border-width:0px;border-radius:0px">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<figure class="wp-block-image size-full is-resized"><img fetchpriority="high" decoding="async" width="1376" height="768" src="https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word.jpg" alt="" class="wp-image-13070" style="object-fit:cover;width:100px;height:70px" srcset="https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word.jpg 1376w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-300x167.jpg 300w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-500x279.jpg 500w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-767x428.jpg 767w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-799x446.jpg 799w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-240x135.jpg 240w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-320x180.jpg 320w" sizes="(max-width: 1376px) 100vw, 1376px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<p class="wp-block-paragraph"><a href="https://www.kazuban.com/blog/ncdata-library-nc-word/" target="_blank">NCワード</a></p>
</div>
</div>



<div class="wp-block-columns has-watery-green-background-color has-background is-style-bottom-margin-1em has-bottom-margin is-layout-flex wp-container-core-columns-is-layout-cb1de518 wp-block-columns-is-layout-flex" style="border-style:none;border-width:0px;border-radius:0px">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<figure class="wp-block-image size-full is-resized"><img decoding="async" width="1376" height="768" src="https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k.jpg" alt="" class="wp-image-13104" style="object-fit:cover;width:100px;height:70px" srcset="https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k.jpg 1376w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-500x279.jpg 500w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-800x447.jpg 800w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-300x167.jpg 300w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-768x429.jpg 768w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-240x135.jpg 240w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-320x180.jpg 320w" sizes="(max-width: 1376px) 100vw, 1376px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<p class="wp-block-paragraph"><a href="https://www.kazuban.com/blog/ncdata-library-nc-comment/">NCコメント</a></p>
</div>
</div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.kazuban.com/blog/ncdata-library-nc-comment/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gコード分析ライブラリ for Python・Ncワード編【Vol.1】</title>
		<link>https://www.kazuban.com/blog/ncdata-library-nc-word/</link>
		
		<dc:creator><![CDATA[kazuban]]></dc:creator>
		<pubDate>Sat, 10 Oct 2026 09:16:12 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[NC]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Claude]]></category>
		<category><![CDATA[ＮＣデータ]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[バイブコーディング]]></category>
		<guid isPermaLink="false">https://www.kazuban.com/blog/?p=13041</guid>

					<description><![CDATA[Ncワード編【Vol.1】 こちらでも、自作ソフトを公開していますが、ほとんどC++Builderで開発しています。 ライブラリも独学なので、動作はしていますが、自分で見直しても綺麗なコードではないですこちらも、AIに頼 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading has-text-align-center">Ncワード編【Vol.1】</h1>



<p class="wp-block-paragraph"><a href="https://www.kazuban.com/blog/free_soft/">こちらでも、自作ソフトを公開</a>していますが、ほとんどC++Builderで開発しています。</p>


<a href="https://www.kazuban.com/blog/free_soft/" title="自作ソフト" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://www.kazuban.com/blog/wp-content/uploads/2025/02/freesoft-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://www.kazuban.com/blog/wp-content/uploads/2025/02/freesoft-160x90.png 160w, https://www.kazuban.com/blog/wp-content/uploads/2025/02/freesoft-120x68.png 120w, https://www.kazuban.com/blog/wp-content/uploads/2025/02/freesoft-320x180.png 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">自作ソフト</div><div class="blogcard-snippet internal-blogcard-snippet">サイト内記事で紹介した、自作ソフトやデータをダウンロードできます。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://www.kazuban.com/blog" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">www.kazuban.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2021.07.11</div></div></div></div></a>


<p class="wp-block-paragraph"><br>ライブラリも独学なので、動作はしていますが、自分で見直しても綺麗なコードではないです<br>こちらも、AIに頼んで見直してもらえば、綺麗になると思いますが、いろんな関数がからみあってて、あまりに量が多いです<br>python学習もかねて、pythonに置き換えてみようと思っています<br>テーマとして、NC用ライブラリのpython化を、無料版Claudeでバイブコーディングを始めました<br>生産性を意識する企業の場合は、Claude Codeが定番なのでしょうが、プログラム言語の学習もかねてAIを利用する場合では、逆にこちらがいい先生になるような気もしてます<br>まずは、NCデータを分解・解析するライブラリを複数回に分けて、記事にする予定です<br>pythonだけでなく、NC言語の説明もしています<br></p>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">NCデータ分析ライブラリ、構造</a><ol><li><a href="#toc2" tabindex="0">NC言語の基本</a></li><li><a href="#toc3" tabindex="0">ライブラリ構成</a></li></ol></li><li><a href="#toc4" tabindex="0">NCワード構文解析「NcWordParser」</a><ol><li><a href="#toc5" tabindex="0">NCブロックの構造</a></li><li><a href="#toc6" tabindex="0">NcWordデータクラス：「Class NcWord」</a></li><li><a href="#toc7" tabindex="0">NCワードパーサー（構造分割）：「class NcWordParser:」</a></li></ol></li><li><a href="#toc8" tabindex="0">NCワードクラス</a></li><li><a href="#toc9" tabindex="0">NC分析ライブラリ、記事一覧</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">NCデータ分析ライブラリ、構造</span></h2>



<h3 class="wp-block-heading"><span id="toc2">NC言語の基本</span></h3>



<p class="wp-block-paragraph">NCデータを分析するには、ある程度、NCデータ構造の理解は必要だと思います<br>コーディングだけなら、言語は知らなくても、AIがコーディングしてくれると思いますが、<br>実際の利用を考えるなら、基本的な理解はしておいたほうがいいと思います<br>NC言語の基本はこのサイトでも、記事にしているので、興味ある方は覗いてみてください<br></p>


<a href="https://www.kazuban.com/blog/nc-gcode-01/" title="NCプログラム／プログラム構造" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="203" height="180" src="https://www.kazuban.com/blog/wp-content/uploads/2019/11/NcData-1.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://www.kazuban.com/blog/wp-content/uploads/2019/11/NcData-1.png 879w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/NcData-1-300x266.png 300w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/NcData-1-768x681.png 768w" sizes="(max-width: 203px) 100vw, 203px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">NCプログラム／プログラム構造</div><div class="blogcard-snippet internal-blogcard-snippet">最近の投稿は、覚書きとしても残しておきたかったので、素人ながらLinux系の投稿が連続していましたが、今回は気分を変えて、今まで携わってきたＮＣ関連の記事を書こうと思います。ＮＣプログラムとは？ＮＣ工作機械のコントローラへの指令の集まりです。プログラムとありますが、ファナック系は基本的には命令コード&#8230;</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://www.kazuban.com/blog" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">www.kazuban.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2019.11.30</div></div></div></div></a>


<h3 class="wp-block-heading"><span id="toc3">ライブラリ構成</span></h3>



<p class="wp-block-paragraph">今回は、C++Builderからの移行と共に、python学習も目的なので、<br>ライブラリ設計はAIに丸投げせず、Claudeに既存のライブラリを添付して、python化をお願いし、コードの意味を説明してもらいながら進めます<br>出力されたコードは、<strong>三項演算子</strong>や<strong>リスト内包表記</strong>など、python特有な書き方の場合もあります<br>今までだったら、参考書開いたり、ネットで検索していましたが、ＡＩは疑問点を聞けばかなり詳細に教えてくれるので、とても便利です</p>



<p class="wp-block-paragraph">まずは、下記３つのライブラリを作成します<br></p>



<div class="wp-block-cocoon-blocks-blank-box-1 blank-box block-box has-background has-watery-green-background-color">
<ul class="wp-block-list">
<li>「NCワード構文解析」：NCワードをアドレスと数字：数値に分解する</li>



<li>「NCコメントを分解」：NCブロックの純粋なコード部分とコメントに分割</li>



<li>「NCブロックを分解・解析」：純粋なNCコードを、「NCワード」に分解し、行の状態（位置座標など）保存・取り出し</li>
</ul>
</div>



<h2 class="wp-block-heading"><span id="toc4">NCワード構文解析「NcWordParser」</span></h2>



<h3 class="wp-block-heading"><span id="toc5">NCブロックの構造</span></h3>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="262" src="https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1-1024x262.png" alt="" class="wp-image-1338" srcset="https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1-1024x262.png 1024w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1-300x77.png 300w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1-768x197.png 768w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1.png 1385w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">「NCブロック」は「NCワード」の集まり<br>「NCワード」は「アドレス（英文字）」と「数字（数値）」で構成されている</p>



<h3 class="wp-block-heading"><span id="toc6">NcWordデータクラス：「Class NcWord」</span></h3>



<p class="wp-block-paragraph">NCワードの変数を格納するクラスを定義します<br>NCワードとしては、データクラスで定義したいを思います<br>４つの変数、<br>「ワード全体」「アドレス」「数値・数字」「Gコード場合、グループ番号」で構成します<br></p>



<pre class="wp-block-preformatted has-black-color has-watery-red-background-color has-text-color has-background">@dataclass
class NcWord:
    word: str = ""  # 元の文字列
    address: str = ""
    value: str = ""
    group: int = -1</pre>



<h3 class="wp-block-heading"><span id="toc7">NCワードパーサー（構造分割）：「class NcWordParser:」</span></h3>



<p class="wp-block-paragraph">NCワード文字列を受け取り、「NcWord」データクラスに分割格納します<br>分割するには、AIは正規表現を教えてくれましたが、NC言語構造には例外もあります<br>通常は「アドレス（英大文字一文字）」+「数値・数字」ですが、特殊な表現が存在します</p>



<blockquote class="wp-block-quote has-watery-yellow-background-color has-background is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">例えば、「G04X10.」の指令・・・１０秒のドウェル指令です<br>これを、「G04」「X10.」と分解すると、「X軸１０mm移動」と誤認識する事になりかねません</p>
</blockquote>



<p class="wp-block-paragraph">他にもあるかもしれませんが、とりあえず思いあたるものは、こんな感じでしょうか？</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">G05P****<br>G54.1P**<br>M98P****<br>M198P****<br>G65P****<br>G66P****<br>G04X****<br>G04P****</p>
</blockquote>



<p class="wp-block-paragraph">この場合、どこまでをアドレスとして扱うか？<br>意見は分かれるところだと思いますが、筆者は上記の英数文字部分（****以外）をアドレスにすることにしました<br>このような判断は、AIに勝手に任せると、後々理解が大変になりそうです<br>やはり、作者の意図をよく伝えて、今のうちからコードに反映させておくのが大事だと思います</p>



<pre class="wp-block-preformatted has-black-color has-watery-red-background-color has-text-color has-background">G_CODE_RE = re.compile(r"G0?5P|G54\.1P|M1?98P|G65P|G66P|G0?4[XP]|[A-Z]")<br><br>def get_NcWord(self, word: str) -&gt; NcWord:<br>    match = self.G_CODE_RE.search(word)<br>    address: str = match.group(0) if match else ""<br>    value: str = word.replace(address, "")<br>    nc_word = NcWord(<br>        word=word,<br>        address=address,<br>        value=value,<br>    )</pre>



<p class="wp-block-paragraph">正規表現で上記の特殊表現と英文字をアドレスと取り出し、アドレス以外を数字として「NcWord」に格納します</p>



<p class="wp-block-paragraph">さらに、面倒くさいのが、モーダルという概念と、Gコードのグループ分けです<br>NCワード単体では判断はできませんが、一行のNCブロックには、同じグループのGコードはNGです<br>また同じグループ番号の場合違うグループ番号が来るまでそのGコードは維持されます。<br>したがって、NcWordデータクラスにはグループ番号も持たせておこうと思います<br>このような、データ構造設計も、作者の考えで違いが出てきます<br>この機能を、AIに聞きながらコード化していきます<br>まずは、Gグループを辞書でデーター化しておきます<br></p>



<pre class="wp-block-preformatted has-black-color has-watery-red-background-color has-text-color has-background">G_GROUPS = {
    "GROUP00": {4, 5, 7, 8, 9, 10, 27, 28, 29, 30, 31, 52, 53, 60, 65, 92},
    "GROUP01": {0, 1, 2, 3},
    "GROUP02": {17, 18, 19},
    "GROUP03": {90, 91},
    "GROUP06": {20, 21, 70, 71},
    "GROUP07": {40, 41, 42},
    "GROUP08": {43, 44, 49},
    "GROUP09": {73, 74, 76, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89},
    "GROUP10": {98, 99},
    "GROUP12": {65, 66, 67},
    "GROUP14": {54, 55, 56, 57, 58, 59},
    "GROUP16": {68, 69},
}</pre>



<p class="wp-block-paragraph">この「G_GROUPS」をもとに、「NcWord」の「group」にグループ番号を入力します<br></p>



<pre class="wp-block-preformatted has-black-color has-watery-red-background-color has-text-color has-background">def get_group(self, word: NcWord) -&gt; None:<br>    """word:NcWord に解析したgroupを設定"""<br>    # _ は一つ目の返り値を無視する意味。<br>    # _analyzeの返り値は、tuple[str, int]<br>    _, group_number = self._analyze(word.address, word.value)<br>    word.group = group_number<br><br>def _analyze(self, address: str, number: str) -&gt; tuple[str, int]:<br>    group_number = -1<br>    group_name = ""<br><br>    match = re.search(r"(G)(0?4|54|65|66)", address)<br>    if match:  # G04X10. / G54.1P1 / G65P9613 対応<br>        address = match.group(1)<br>        number = match.group(2)<br>    if address != "G":<br>        return group_name, group_number<br>    for n, v in self.G_GROUPS.items():<br>        if int(number) in v:<br>            group_number = int(n.replace("GROUP", ""))<br>            group_name = n<br>            break<br>    return group_name, group_number</pre>



<h2 class="wp-block-heading"><span id="toc8">NCワードクラス</span></h2>



<p class="wp-block-paragraph">実際の、コード「<strong>nc_word.py</strong>」を添付します</p>



<pre class="wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-2"><code>import re
from dataclasses import dataclass
from typing import Optional 


@dataclass
class NcWord:
    word: str = ""  # 元の文字列
    address: str = ""
    value: str = ""
    group: int = -1


class NcWordParser:
    G_CODE_RE = re.compile(r"G0?5P|G54\.1P|M1?98P|G65P|G66P|G0?4&#91;XP]|&#91;A-Z]")

    def get_NcWord(self, word: str) -&gt; NcWord:  # -&gt; Optional&#91;NcWord]:
        # if not word:
        #    return None
        match = self.G_CODE_RE.search(word)
        address: str = match.group(0) if match else ""
        value: str = word.replace(address, "")
        nc_word = NcWord(
            word=word,
            address=address,
            value=value,
        )
        GroupAnalyzer(nc_word)
        return nc_word


class GroupAnalyzer:
    """NCワード文字列のGコードからGグループを解析"""

    G_GROUPS = {
        "GROUP00": {4, 5, 7, 8, 9, 10, 27, 28, 29, 30, 31, 52, 53, 60, 65, 92},
        "GROUP01": {0, 1, 2, 3},
        "GROUP02": {17, 18, 19},
        "GROUP03": {90, 91},
        "GROUP06": {20, 21, 70, 71},
        "GROUP07": {40, 41, 42},
        "GROUP08": {43, 44, 49},
        "GROUP09": {73, 74, 76, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89},
        "GROUP10": {98, 99},
        "GROUP12": {65, 66, 67},
        "GROUP14": {54, 55, 56, 57, 58, 59},
        "GROUP16": {68, 69},
    }

    def __init__(self, nc_word: Optional&#91;NcWord] = None) -&gt; None:
        if nc_word:
            self.get_group(nc_word)

    def get_group(self, word: NcWord) -&gt; None:
        """word:NcWord に解析したgroupを設定"""
        # _ は一つ目の返り値を無視する意味。
        # _analyzeの返り値は、tuple&#91;str, int]
        _, group_number = self._analyze(word.address, word.value)
        word.group = group_number

    def _analyze(self, address: str, number: str) -&gt; tuple&#91;str, int]:
        group_number = -1
        group_name = ""

        match = re.search(r"(G)(0?4|54|65|66)", address)
        if match:  # G04X10. / G54.1P1 / G65P9613 対応
            address = match.group(1)
            number = match.group(2)
        if address != "G":
            return group_name, group_number
        for n, v in self.G_GROUPS.items():
            if int(number) in v:
                # group_number = int(util.extract_numbers(n, 2))
                group_number = int(n.replace("GROUP", ""))
                group_name = n
                break
        return group_name, group_number


# test code
if __name__ == "__main__":
    gcode = &#91;"G54", "G00", "G17", "G54.1P5", "G01", "G04X10.", "X20.325"]
    print("「実行結果」")
    for word in gcode:
        ncw: NcWord = NcWordParser().get_NcWord(word)
        print(ncw)
</code></pre>



<p class="wp-block-paragraph">取り込んだ、NCワードデータを、アドレスと数字に分解し、アドレスが　&#8221;G&#8221;の場合、Gコードグループ番号を「NcWord」にセットします。<br>テストコード（test code）をライブラリ末尾に付加して実行してみます</p>



<pre class="wp-block-preformatted">python nc_word.py<br><br>「実行結果」<br>NcWord(word='G54', address='G', value='54', group=14)<br>NcWord(word='G00', address='G', value='00', group=1)<br>NcWord(word='G17', address='G', value='17', group=2)<br>NcWord(word='G54.1P5', address='G54.1P', value='5', group=14)<br>NcWord(word='G01', address='G', value='01', group=1)<br>NcWord(word='G04X10.', address='G04X', value='10.', group=0)<br>NcWord(word='X20.325', address='X', value='20.325', group=-1)</pre>



<p class="wp-block-paragraph">希望通り、渡したNCワード文字列から、NcWordクラスのフィールドに格納されました</p>



<h2 class="wp-block-heading has-vivid-cyan-blue-to-vivid-purple-gradient-background has-background" style="border-style:none;border-width:0px"><span id="toc9">NC分析ライブラリ、記事一覧</span></h2>



<div class="wp-block-columns has-watery-red-background-color has-background is-style-bottom-margin-1em has-bottom-margin is-layout-flex wp-container-core-columns-is-layout-cb1de518 wp-block-columns-is-layout-flex" style="border-style:none;border-width:0px;border-radius:0px">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<figure class="wp-block-image size-full is-resized"><a href="https://www.kazuban.com/blog/ncdata-library-nc-word/"><img loading="lazy" decoding="async" width="1376" height="768" src="https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word.jpg" alt="" class="wp-image-13070" style="object-fit:cover;width:100px;height:70px" srcset="https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word.jpg 1376w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-300x167.jpg 300w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-500x279.jpg 500w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-767x428.jpg 767w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-799x446.jpg 799w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-240x135.jpg 240w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/ncdata-library-nc-word-320x180.jpg 320w" sizes="(max-width: 1376px) 100vw, 1376px" /></a></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<p class="wp-block-paragraph"><a href="https://www.kazuban.com/blog/ncdata-library-nc-word/">NCワード編</a></p>
</div>
</div>



<div class="wp-block-columns has-watery-green-background-color has-background is-style-bottom-margin-1em has-bottom-margin is-layout-flex wp-container-core-columns-is-layout-cb1de518 wp-block-columns-is-layout-flex" style="border-style:none;border-width:0px;border-radius:0px">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1376" height="768" src="https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k.jpg" alt="" class="wp-image-13104" style="object-fit:cover;width:100px;height:70px" srcset="https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k.jpg 1376w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-500x279.jpg 500w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-800x447.jpg 800w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-300x167.jpg 300w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-768x429.jpg 768w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-240x135.jpg 240w, https://www.kazuban.com/blog/wp-content/uploads/2026/09/Gemini_Generated_Image_ud5k15ud5k15ud5k-320x180.jpg 320w" sizes="(max-width: 1376px) 100vw, 1376px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<p class="wp-block-paragraph"><a href="https://www.kazuban.com/blog/ncdata-library-nc-comment/" target="_blank">NCコメント</a></p>
</div>
</div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Python正規表現に挑戦 ― Fanuc系NCブロックをNCワードに分解させる</title>
		<link>https://www.kazuban.com/blog/python-regex/</link>
		
		<dc:creator><![CDATA[kazuban]]></dc:creator>
		<pubDate>Thu, 05 Feb 2026 00:40:01 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[NC]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[G-Code]]></category>
		<category><![CDATA[ＮＣデータ]]></category>
		<category><![CDATA[NCプログラム]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[正規表現]]></category>
		<guid isPermaLink="false">https://www.kazuban.com/blog/?p=12021</guid>

					<description><![CDATA[このサイトでは、NCデータの解析・変換などの自作アプリを公開しています。これまでは C++Builder で自作ライブラリを作成し開発してきました。独学ゆえに効率や可読性など課題は沢山ありますが、いまさら見直す気にもなり [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">このサイトでは、<a href="https://www.kazuban.com/blog/free_soft/">NCデータの解析・変換などの自作アプリを公開</a>しています。<br>これまでは C++Builder で自作ライブラリを作成し開発してきました。<br>独学ゆえに効率や可読性など課題は沢山ありますが、いまさら見直す気にもなりません。<br>最近は Python の学習もかねてNCデータ解析ライブラリのpythonへの移行を考えています。<br>AI の登場で、素人でも高度なコードを得られる時代になりましたが、意味を理解せずに使うのはやはり危険ですし、プログラミングスキルは向上しません。<br>この記事を書くきっかけは<br>「Fanuc系NCブロックをNCワードに分割させる、pythonスクリプトをだして」<br>へのAIの回答に正規表現が使われていた事から始まりました<br>本記事では、「一見意味不明な呪文のような正規表現」を理解して行く過程を記事にしました。</p>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-6" checked><label class="toc-title" for="toc-checkbox-6">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">正規表現</a><ol><li><a href="#toc2" tabindex="0">概要</a></li><li><a href="#toc3" tabindex="0">1. 文字列とリテラル</a></li><li><a href="#toc4" tabindex="0">2. メタ文字（特別な意味を持つ記号）</a><ol><li><a href="#toc5" tabindex="0">具体例</a></li></ol></li><li><a href="#toc6" tabindex="0">3. 繰り返し回数の指定（量指定子）</a><ol><li><a href="#toc7" tabindex="0">具体例</a></li></ol></li><li><a href="#toc8" tabindex="0">4. 文字クラス</a></li><li><a href="#toc9" tabindex="0">5. 代表的なエスケープシーケンス</a></li><li><a href="#toc10" tabindex="0">6. エスケープが必要な記号</a></li><li><a href="#toc11" tabindex="0">補足</a></li></ol></li><li><a href="#toc12" tabindex="0">ファナック系、NCデータ構造</a><ol><li><a href="#toc13" tabindex="0">
「ワード」＝「アドレス」+「数字・数値」
「ブロック」＝「ワード」の集まり
「NCデータ」＝「ブロック」の集まり
</a></li></ol></li><li><a href="#toc14" tabindex="0">ブロックから正規表現でワードに分解する</a><ol><li><a href="#toc15" tabindex="0">アドレスと数字抽出</a></li><li><a href="#toc16" tabindex="0">さらに、アドレスと数字を分けて抽出したい場合</a></li><li><a href="#toc17" tabindex="0">軸（X,Y,Z・・）の小数点にも対応させる</a></li><li><a href="#toc18" tabindex="0">複雑な正規表現の可読性を高める</a></li><li><a href="#toc19" tabindex="0">さらにちょっと特殊な、G や M　コードにも対応させてみます</a></li><li><a href="#toc20" tabindex="0">正規表現のraw文字列の変数化</a></li></ol></li><li><a href="#toc21" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">正規表現</span></h2>



<p class="wp-block-paragraph">正規表現の情報は、ネット上に豊富にあると思うので、詳細は検索してみてください。<br>下記は「正規表現」の説明をAIに聞いてみた回答です</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<h3 class="wp-block-heading"><span id="toc2"><a>概要</a></span></h3>



<p class="wp-block-paragraph">本チャットログでは、「正規表現（Regular Expression）」の基本要素について、最小限かつ代表的な機能に絞って説明している。主な用途は文字列の検索・置換・抽出であり、「文字列パターンを表現する小さな言語」として位置付けている。</p>



<h3 class="wp-block-heading"><span id="toc3"><a>1. </a>文字列とリテラル</span></h3>



<ul class="wp-block-list">
<li>abc
<ul class="wp-block-list">
<li>文字列「abc」にそのままマッチするパターン。</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading"><span id="toc4"><a>2. </a>メタ文字（特別な意味を持つ記号）</span></h3>



<ul class="wp-block-list">
<li>. : 任意の1文字</li>



<li>^ : 行頭</li>



<li>$ : 行末</li>



<li>* : 直前要素の0回以上の繰り返し</li>



<li>+ : 直前要素の1回以上の繰り返し</li>



<li>? : 直前要素の0回または1回</li>



<li>| : OR（または）</li>



<li>() : グループ化・キャプチャ</li>
</ul>



<h4 class="wp-block-heading"><span id="toc5"><a>具体例</a></span></h4>



<ul class="wp-block-list">
<li>a.*b
<ul class="wp-block-list">
<li>「a」で始まり「b」で終わる行全体にマッチ（間の文字列は任意長）</li>
</ul>
</li>



<li>colou?r
<ul class="wp-block-list">
<li>color または colour にマッチ（u がある/ない両方に対応）。</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading"><span id="toc6"><a>3. </a>繰り返し回数の指定（量指定子）</span></h3>



<ul class="wp-block-list">
<li>{n} : ちょうど n 回</li>



<li>{n,} : n 回以上</li>



<li>{n,m} : n〜m 回</li>
</ul>



<h4 class="wp-block-heading"><span id="toc7"><a>具体例</a></span></h4>



<ul class="wp-block-list">
<li>\d{3}-\d{4}
<ul class="wp-block-list">
<li>123-4567 のような「数字3桁-数字4桁」形式にマッチ。</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading"><span id="toc8"><a>4. </a>文字クラス</span></h3>



<ul class="wp-block-list">
<li>[abc] : a か b か c のいずれか1文字</li>



<li>[^abc] : a,b,c 以外の1文字</li>



<li>[0-9] : 数字</li>



<li>[A-Za-z] : 英字（大文字・小文字）</li>
</ul>



<h3 class="wp-block-heading"><span id="toc9"><a>5. </a>代表的なエスケープシーケンス</span></h3>



<p class="wp-block-paragraph">多くの処理系で共通して使われるもの。</p>



<ul class="wp-block-list">
<li>\d : 数字 [0-9]</li>



<li>\w : 単語構成文字（英数字 + _）</li>



<li>\s : 空白文字（スペース・タブ・改行など）</li>



<li>\D : 非数字（\d 以外）</li>



<li>\W : 非単語構成文字（\w 以外）</li>



<li>\S : 非空白文字（\s 以外）</li>
</ul>



<h3 class="wp-block-heading"><span id="toc10"><a>6. </a>エスケープが必要な記号</span></h3>



<p class="wp-block-paragraph">次の文字はメタ文字として特別な意味を持つため、そのままの記号として扱うにはバックスラッシュでエスケープする必要がある。</p>



<ul class="wp-block-list">
<li>対象文字
<ul class="wp-block-list">
<li>. * + ? ^ $ ( ) [ ] { } | \</li>
</ul>
</li>



<li>使用例<ul><li>\. : ドットそのものにマッチ</li></ul>
<ul class="wp-block-list">
<li>\? : 疑問符そのものにマッチ</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading"><span id="toc11"><a>補足</a></span></h3>



<p class="wp-block-paragraph">ここまでが「基本の道具」としての正規表現の要素一式であり、今後はこれらを組み合わせて「メールアドレスの簡易チェック」など、実用的なパターン作成にも応用できると示唆している。</p>
</blockquote>



<p class="wp-block-paragraph">個別でみれば、なんとなくわかる気もしますが、これが組み合わさると、まったく呪文です<br>ただ、いろんなパターンの質問とAIの回答を照らし合わせると、なんとなく理解できてくるので、正規表現にかぎらず、AIは言語学習資料としても本当に役立ちます。</p>



<h2 class="wp-block-heading"><span id="toc12">ファナック系、NCデータ構造</span></h2>



<p class="wp-block-paragraph">NCデータの分析ソフトを検討する場合、NCデータ構造の知識は必須です<br>NCデータの知識がないまま、AIの回答だけで進めると、間違いなく後々苦労します<br>ファナック系のプログラム構造は、下記記事でも紹介しています</p>



<figure class="wp-block-embed is-type-wp-embed"><div class="wp-block-embed__wrapper">

<a href="https://www.kazuban.com/blog/nc-gcode-01/#toc2" title="NCプログラム／プログラム構造" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="203" height="180" src="https://www.kazuban.com/blog/wp-content/uploads/2019/11/NcData-1.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://www.kazuban.com/blog/wp-content/uploads/2019/11/NcData-1.png 879w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/NcData-1-300x266.png 300w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/NcData-1-768x681.png 768w" sizes="(max-width: 203px) 100vw, 203px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">NCプログラム／プログラム構造</div><div class="blogcard-snippet internal-blogcard-snippet">最近の投稿は、覚書きとしても残しておきたかったので、素人ながらLinux系の投稿が連続していましたが、今回は気分を変えて、今まで携わってきたＮＣ関連の記事を書こうと思います。ＮＣプログラムとは？ＮＣ工作機械のコントローラへの指令の集まりです。プログラムとありますが、ファナック系は基本的には命令コード...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://www.kazuban.com/blog" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">www.kazuban.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2019.11.30</div></div></div></div></a>
</div></figure>



<h3 class="wp-block-heading has-text-align-left"><span id="toc13">
「ワード」＝「アドレス」+「数字・数値」<br>
「ブロック」＝「ワード」の集まり<br>
「NCデータ」＝「ブロック」の集まり
</span></h3>



<p class="wp-block-paragraph">NCブロックからNCアドレスを抽出する課題なので、NCコードを少し復習しておきます</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="262" src="https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1-1024x262.png" alt="" class="wp-image-1338" srcset="https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1-1024x262.png 1024w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1-300x77.png 300w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1-768x197.png 768w, https://www.kazuban.com/blog/wp-content/uploads/2019/11/図1.png 1385w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">ブロックの末尾は制御器では「EOB」ですが、PC側では改行コードになります<br>改行コードはOSにより変わりますが、基本的にアスキー形式での転送で大丈夫だと思います<br>NCデータの最小単位は、「ワード」と呼ばれていて、<br>「アルファベット一文字」+「数字、符号、小数点」が一塊になっている要素です<br>例えば「G02」とか「X-12.345」の構成です。<br>先頭のアドレス文字で機械への指令の種類を表し、ワードで具体的な指令になります<br>この「ワード」が集まり、一行の構成になった文字列が「ブロック」と呼ばれます<br>さらに、「ブロック」が複数行あつまって、NCデータになります<br>CAM利用の場合、作成したNCデータファイルをNC機械へ転送し加工動作を制御します<br>分析ソフトを検討する場合、まずはNCデータをブロックに、ブロックをワードに分解したほうが整理しやすいです<br>今回の課題では、<span class="marker-under-red">正規表現</span>を利用して<span class="marker-under">「ブロック」を「ワード」に分解する</span>コードを作成します<br>やりたい事をAIに投げかけると、それなりの回答をもらえます。<br>ただ、ＮＣコードのように、機種依存や複雑な表現がある場合、AIへすべて完ぺきなコードを期待してもなかなか思うような回答は得られません。<br>また、最初は良くても開発を進めていくうちに、改造したくなる場合もあります<br>やはり、ある程度の理解は必要です。</p>



<h2 class="wp-block-heading"><span id="toc14">ブロックから正規表現でワードに分解する</span></h2>



<p class="wp-block-paragraph">具体的に正規表現を書き、「ワード」に分解した結果と照らし合わせながら理解を進めようと思います<br>「ワード」＝「大文字アルファベット一文字」+「数字」なので、一番単純な正規表現のパターンは、&#8221;[A-Z]\d&#8221;になります<br>また、正規表現パターンで、文字列から部分文字列を抽出するのに、AIは「re.findall関数」を教えてくれました<br>（findall関数についての詳細は、ネット検索やAIに聞いてみてください）<br>サンプル文字列は複数のパターンを織り交ぜた、&#8221;G0G1G00 G03M3 T102M30&#8243;　でやってみます<br>（文字列並びのみのサンプルで、NCデータとしては意味ありません）</p>



<h3 class="wp-block-heading"><span id="toc15">アドレスと数字抽出</span></h3>



<pre class="wp-block-code"><code>import re

block = "G0G1G00 G03M3 T102M30" # サンプルNCブロック文字列
words = re.findall(r"<strong>&#91;A-Z]\d</strong>", block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'G0', 'G1', 'G0', 'G0', 'M3', 'T1', 'M3']</code></pre>



<p class="wp-block-paragraph">ちょっと期待とは違いますが、とりあえずは、アドレスと数字がリストで取り出せました<br>たった一行で分解された文字列リストが作成されました、すごいですね～<br>一文字づつ文字列操作で処理させたら、結構なコード量になっていると思います<br>ただ、「\d」としたため、「数字は<strong>一文字</strong>」しか抽出してくれませんでした<br>ここで「\d{2}」としてみると、「数字二文字」のみ取り出してくれます<br>今回の例ですべて取り出すには「\d{1,3}」とすればすべてヒットします<br>「\d+」でも同様の結果になりますが、こちらの方は文字数制限はなくなります<br>今回のサンプルでは、&#8221;[A-Z]\d+&#8221;で行こうと思います<br>ちなみに、「\d{0}」とすると、アドレスのみ取り出せます。</p>



<pre class="wp-block-code"><code>import re

block = "G0G1G00 G03M3 T102M30" # サンプルNCブロック文字列
words = re.findall(r"<strong>&#91;A-Z]\d+</strong>", block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'G0', 'G1', 'G00', 'G03', 'M3', 'T102', 'M30']</code></pre>



<h3 class="wp-block-heading"><span id="toc16">さらに、アドレスと数字を分けて抽出したい場合</span></h3>



<p class="wp-block-paragraph">グループ化と呼ばれる（丸括弧）でパターンを囲むと「tuple」として分離してくれます<br>抽出した後の処理内容によっては、こちらが便利かもしれません</p>



<pre class="wp-block-code"><code>import re

block = "G0G1G00 G03M3 T102M30" # サンプルNCブロック文字列
words = re.findall(r"<strong>(&#91;A-Z])(\d+)</strong>", block)
print(f"{words}")
for addr, val in words:
    print(f"addr={addr}:val={val}")

#---------- 結果 --------------
#&#91;('G', '0'), ('G', '1'), ('G', '00'), ('G', '03'), ('M', '3'), ('T', '102'), ('M', '30')]
#addr=G:val=0
#addr=G:val=1
#addr=G:val=00
#addr=G:val=03
#addr=M:val=3
#addr=T:val=102
#addr=M:val=30</code></pre>



<h3 class="wp-block-heading"><span id="toc17">軸（X,Y,Z・・）の小数点にも対応させる</span></h3>



<p class="wp-block-paragraph">ここまでは、GやMコードでしたが、軸指令に対応するには、<span class="marker-under">符号や小数点</span>も考慮する必要があります<br>余談ですがプログラミング初心者の場合勘違いしやすいのが、<span class="marker-under-red"><strong>数字</strong>と<strong>数値</strong>の違い</span>です。<br>「12.23」の場合、<strong>数値</strong>としては「12 + 0.23」のように演算ができますが、<br><strong>数字</strong>の場合は、「1」「2」「.」「2」「3」と途中に「.」があるだけのただの数字文字の連続です<br>正規表現の場合も、数字・符号・小数点の<strong>文字の集まり</strong>として処理するので、数値で考えてしまうと期待と違う結果になり、悩む事になります<br>さて、文字を意識してサンプル文字列データに軸指令を追加して、上記のコードで実行してみます</p>



<pre class="wp-block-code"><code>import re

block = "G90G01 <strong>X12.5Y+20.3Z-5.63</strong>F1000" # サンプルNCブロック文字列
words = re.findall(r"<strong>&#91;A-Z]\d+</strong>", block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'G90', 'G01', 'X12', 'F1000']</code></pre>



<p class="wp-block-paragraph">やはりこのコードでは、±符号と小数点が入るとマッチしないので、省かれてしまいますね<br>まず符号に対応するためにはアドレス「A-Z」の後に[+-]を追加します</p>



<pre class="wp-block-code"><code>import re

block = "G90G01 X12.5Y+20.3Z-5.63F1000" # サンプルNCブロック文字列
words = re.findall(r"<strong>&#91;A-Z]&#91;+-]\d+</strong>", block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'Y+20', 'Z-5']</code></pre>



<p class="wp-block-paragraph">これでは、符号「+-」が必須に判断され符号付の文字列しかヒットしませんでした<br>符号文字は<span class="marker-under">「無くてもいい」</span>の意味で<span class="marker-under"><strong>[+-]?</strong></span>としてみます</p>



<pre class="wp-block-code"><code>import re

block = "G90G01 X12.5Y+20.3Z-5.63F1000" # サンプルNCブロック文字列
words = re.findall(r"<strong>&#91;A-Z]&#91;+-]?\d+</strong>", block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'G90', 'G01', 'X12', 'Y+20', 'Z-5', 'F1000']</code></pre>



<p class="wp-block-paragraph">符号部分を<span class="marker">[+-]?</span> とすることで、符号がなくてもマッチするようになりました<br>次に小数点とそれ以下にも対応させてみましょう<br>NC制御器は、数値として扱いますが、文字としての小数点の扱いは結構面倒です。<br>小数点がある場合、ない場合、小数点から始まる場合、小数点で終わる場合・・など<br>まずは、小数点の有無に対応させるため、「<strong>\d+\.\d+</strong>」を考えましたが、<br>この場合、小数点がないとマッチしなくなります<br>そこで「？を付加」すれば「無くてもいい」にも対応できます</p>



<pre class="wp-block-code"><code>import re

block = "G90G01 X12.5Y+20.3Z-5.63F1000" # サンプルNCブロック文字列
words = re.findall(r"<strong>&#91;A-Z]&#91;+-]?\d+\.?\d+</strong>", block)
print(f"{words}")

#---------- 結果 --------------
&#91;'G90', 'G01', 'X12.5', 'Y+20.3', 'Z-5.63', 'F1000']
</code></pre>



<p class="wp-block-paragraph">だいぶ理想に近づいてきましたが、「X.124」や「23.」など、小数点での始まりや終わりには対応できません<br>サンプル文字列に追加して確かめてみましょう</p>



<pre class="wp-block-code"><code>import re

block = "G90G01 X12.50Y+20.3Z-5.63 <span class="marker"><strong>I.5 J22.</strong></span>F1000" # サンプルNCブロック文字列
words = re.findall(r"<strong>&#91;A-Z]&#91;+-]?\d+\.?\d+"</strong>, block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'G90', 'G01', 'X12.50', 'Y+20.3', 'Z-5.63', '<span class="marker-red">J22</span>', 'F1000</code></pre>



<p class="wp-block-paragraph">やはり、「I.5」にはマッチせず「J22.」の「.」は省かれていますね<br>ここも余談ですが、NCで「<strong>22.</strong>」を「<strong>22</strong>」に変換してしまった場合、制御器によってはとんでもない事になりかねないので十分意識しておく必要があります。<br><br>整理してみると</p>



<ul class="wp-block-list">
<li>[A-Z]：NCコードのアドレス</li>



<li>[+-]?：必須ではない、符号</li>



<li>\d+：複数個の数字<br>ここまでで、「Gコード」「Mコード」には対応できている</li>



<li>\.?：小数点は必須でない</li>



<li>\d+：複数個の数字</li>
</ul>



<p class="wp-block-paragraph">やはり、「小数点で終わる」場合「\.?」なので、省略されてしまいますね<br>ではどうすればいのか？<br>AIに聞いたところ、グループ化と言う方法があり、&#8221;( )&#8221;で囲む事で、一塊としてでマッチングのルール設定できるようです<br>ただし、&#8221;( )&#8221;では、囲みごとに分割されタプルのリストとして抽出されます<br>グループごとに分割させたくない場合には<span class="marker-under"><strong>&#8220;(?: )</strong>&#8220;で囲む</span>仕様があり<span class="marker-under">非キャプチャグループ</span>と呼ばれマッチングのルールには使用するが分割はされないようです。<br>今回の例では、分割させたくないので、&#8221;<strong>(?: )</strong>&#8220;を使ってみます<br>最後の「\d+：複数個の数字」をグループ化して、必須ではない複数個の数字として設定します</p>



<pre class="wp-block-code"><code>import re

block = "G90G01 X12.50Y+20.3Z-5.63 <span class="marker"><strong>I.5 J22.</strong></span>F1000" # サンプルNCブロック文字列
words = re.findall(r"&#91;A-Z]&#91;+-]?\d+\.?<strong>(?:\d+)?</strong>", block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'G90', 'G01', 'X12.50', 'Y+20.3', 'Z-5.63', '<span class="marker"><strong>J22.</strong></span>', 'F1000']</code></pre>



<p class="wp-block-paragraph">これで、「22.」には対応できました。次は、小数点で始まる「.5」の場合です。<br>ここまででも、結構な呪文になっているのに、さらに複雑になりそうです。<br>ここもAIに相談すると、グループの中で（A | B）の書式で「AまたはB」とマッチング範囲の選択ができるようで、この書式での書き方を教えてくました</p>



<pre class="wp-block-code"><code>import re

block = "G90G01 X12.50Y+20.3Z-5.63 <span class="marker"><strong>I.5 J22.</strong></span>F1000" # サンプルNCブロック文字列
words = re.findall(r"&#91;A-Z]&#91;+-]?(?:<span class="marker-under-blue">\d+\.\d+</span><strong>|</strong><span class="marker-under">\d+\.</span><strong>|</strong><span class="marker-under-red">\.\d+</span><strong>|</strong>\d+)", block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'G90', 'G01', 'X12.50', 'Y+20.3', 'Z-5.63', <span class="marker"><strong>'I.5'</strong>, <strong>'J22.'</strong></span>, 'F1000']</code></pre>



<ul class="wp-block-list">
<li>[A-Z]：NCコードのアドレス</li>



<li>[+-]?：必須ではない、符号</li>



<li>&#8212; ここからグループ化 &#8212;</li>



<li>\d+\.\d+：数字+小数点+数字<br>または</li>



<li>\d+\.：数字+小数点<br>または</li>



<li>\.\d+:小数点+数字<br>または</li>



<li>\d+：複数個の数字のみ</li>
</ul>



<p class="wp-block-paragraph">書き方は他にもあると思いますが、グループ化して、マッチさせたいパターンを一つ一つORで区切るこの方法は私には理解しやすかったです</p>



<h3 class="wp-block-heading"><span id="toc18">複雑な正規表現の可読性を高める</span></h3>



<p class="wp-block-paragraph">いちおう動作はしましたが、ここまでくると、読みにくいですね～<br>可読性を高める方法として、さらにAIが「re.VERBOSE」を提案してくれました<br>具体的に、上記のコードを書き替えてみます<br>パターンを一行づつに分割できて、行ごとにコメントも追記できるので、複雑になってもわかりやすくなります</p>



<pre class="wp-block-code"><code>pattern = re.compile(
    r"""
    &#91;A-Z]        # A-Zアドレス
    &#91;+-]?         # 符号
    (?:           # 小数点処理、非キャプチャグループ
      \d+\.\d+      # 数字、小数点、数字
      |\d+\.        # または、数字、小数点
      |\.\d+        # または、小数点、数字
      |\d+          # または、数字のみ
    )
    """,
    re.VERBOSE,
)
words = pattern.findall(block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'G90', 'G01', 'X12.50', 'Y+20.3', 'Z-5.63', 'I.5', 'J22.', 'F1000']</code></pre>



<h3 class="wp-block-heading"><span id="toc19">さらにちょっと特殊な、G や M　コードにも対応させてみます</span></h3>



<p class="wp-block-paragraph">通常、NCワードは「アドレス＋数字」ですが、拡張されたワーク座標系指令やサブプロ呼び出しなどちょっと特殊な構成のコードもあります<br>全てに対応は難しいと思いますが、「G54.1P1」や「M98P100」などにも対応してみようと思います。<br>これら対応するためには、上記のパターンでは処理できないのでパターンを追加します<br>やはり、可読性が上がる、re.VERBOSE を利用します</p>



<pre class="wp-block-code"><code>block = (
    "G05P10000 G90G01 X12.50Y+20.3Z-5.63 I.5 J22.F1000 G54 G54.1P12 M98P1100 M198 P2299"
)
pattern = re.compile(
    r"""
    # --- 特殊構成、G54.1P12 / M98P1234　など---
    &#91;GM]          # G や M アドレス
    \d+(?:\.\d+)? # 54　や　54.1 
    \s*P\d+       # スペースとP文字と数字
    # --- 通常のアドレス+数字 ----
    |&#91;A-Z]        # A-Zアドレス
    &#91;+-]?         # 符号
    # --- 小数点対応 ----
    (?:           # 非キャプチャグループ
      \d+\.\d+      # 数字、小数点、数字
      |\d+\.        # または、数字、小数点
      |\.\d+        # または、小数点、数字
      |\d+          # または、数字のみ
    )
    """,
    re.VERBOSE,
)
words = pattern.findall(block)
print(f"{words}")

#---------- 結果 --------------
#&#91;'G05P10000', 'G90', 'G01', 'X12.50', 'Y+20.3', 'Z-5.63', 'I.5', 'J22.', 'F1000', 'G54', 'G54.1P12', 'M98P1100', 'M198 P2299']</code></pre>



<p class="wp-block-paragraph">どうにかできました。<br>次の課題は「G04X10.」とかにも対応したいと思っていますが、これ以上条件が増えると大変です<br>正規表現パターンを変数化できれば、もう少しわかりやすいと思います</p>



<h3 class="wp-block-heading"><span id="toc20">正規表現のraw文字列の変数化</span></h3>



<p class="wp-block-paragraph">AIに聞いてみました。さすがAI、できますよ！との回答をもらいました<br>AIの回答を参考に上記コードを書き直してみました。</p>



<pre class="wp-block-code"><code>block = (
    "G05P10000 G90G01 X12.50Y+20.3Z-5.63 I.5 J22.F1000 G54 G54.1P12 M98P1100 M198 P2299"
)
num = r"&#91;+-]?(?:\d+\.\d+|\d+\.|\.\d+|\d+)"  # +12.123|-24.|.56|30
g54_1 = r"&#91;GM]\d+(?:\.\d+)?\s*P\d+\.?"      # G54.1P1 M98P1122
nomal = r"&#91;A-Z]"  # 通常のアドレス
pattern = re.compile(
    rf"""     
    {g54_1}         # G54.1P1 , M98P1122
    #----------------------
    |{nomal}{num}   # G01 , X-12.356
    """,
    re.VERBOSE,
)
words = pattern.findall(block)
#---------- 結果 --------------
#&#91;'G05P10000', 'G90', 'G01', 'X12.50', 'Y+20.3', 'Z-5.63', 'I.5', 'J22.', 'F1000', 'G54', 'G54.1P12', 'M98P1100', 'M198 P2299']</code></pre>



<p class="wp-block-paragraph">なるほど、だいぶ見やすくなりました<br>今後の仕様変更にも対応しやすくなったと思います<br>興味ある方は是非、「G04X10.」への対応もやってみてください。</p>



<h2 class="wp-block-heading"><span id="toc21">まとめ</span></h2>



<p class="wp-block-paragraph">これまでも単純な正規表現に触れる機会はありましたが、複雑な記述はまるで「呪文」のようで、敬遠していました。 <br>しかし、正規表現は文字列操作において非常に強力な武器になります。<br>独学ではやる気なしでしたが、AIと対話する事で、ある程度は理解できてきました。<br> 今後もAIと対話しながら一歩ずつ分析していくことで、正規表現だけでなく、プログラミング言語全体の理解力も深めていけると感じています。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Fusion360 APIでTkinterを使ってみた。単純UIならこれでよくない？ボタンクリックでXYZ軸の基準線を作図するFusionスクリプトを実行させてみた</title>
		<link>https://www.kazuban.com/blog/python-api-tkinter01/</link>
		
		<dc:creator><![CDATA[kazuban]]></dc:creator>
		<pubDate>Fri, 09 Jan 2026 04:52:45 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Fusion360]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://www.kazuban.com/blog/?p=11788</guid>

					<description><![CDATA[少し前から、Python 学習の一環として AI に相談しながら Fusion 360 の API を触っており、その過程を以前の記事で紹介しました。 この記事では、Fusionの標準APIの2D スケッチで頻繁に使うオ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">少し前から、Python 学習の一環として AI に相談しながら Fusion 360 の API<strong> </strong>を触っており、その過程を以前の記事で紹介しました。</p>



<figure class="wp-block-embed is-type-wp-embed"><div class="wp-block-embed__wrapper">

<a href="https://www.kazuban.com/blog/fusion-python-api/" title="Fusion360  Python API 再挑戦！AIの力を借りて、sketchなど基本ライブラリを作ってみた。" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://www.kazuban.com/blog/wp-content/uploads/2025/07/fusion-python-api-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://www.kazuban.com/blog/wp-content/uploads/2025/07/fusion-python-api-160x90.png 160w, https://www.kazuban.com/blog/wp-content/uploads/2025/07/fusion-python-api-120x68.png 120w, https://www.kazuban.com/blog/wp-content/uploads/2025/07/fusion-python-api-320x180.png 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Fusion360  Python API 再挑戦！AIの力を借りて、sketchなど基本ライブラリを作ってみた。</div><div class="blogcard-snippet internal-blogcard-snippet">Aiと言う強い味方を得て、Fusion API に再挑戦しています。pythonの学習もかねて、skrtch関連の関数をライブラリ化しています。筆者の環境では、正常に動作しています。コピペで利用可。Aiに教えてもらわないと、作成できなかった実例をレポートしています。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://www.kazuban.com/blog" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">www.kazuban.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2025.07.09</div></div></div></div></a>
</div></figure>



<p class="wp-block-paragraph">この記事では、Fusionの標準APIの2D スケッチで頻繁に使うオブジェクトをカプセル化しライブラリとしてまとめてみました。<br>Fusion 360 はパラメトリックモデリングを前提としているため、まずラフに図形を描き、あとから寸法線や拘束を追加して形状を詰めていく、という作業フローが基本です。<br>試行錯誤しながら設計を煮詰めていく用途では非常に強力な手法ですが、CAM 作業のように、すでに図面や数値が確定している場合には、この手順がやや回りくどく感じることもあります。<br>またFusion 360 には原点の概念はありますが、原点を強く意識しないモデリング手法であるため、「図面ありき」の CAM 作業では、座標原点を通る中心線作図から始めるようにしています<br>ところが、この最初に描いた中心線も拘束や固定を忘れると、気づかないうちに移動させてしまい、後工程で大きなトラブルになることがあります。</p>



<p class="has-watery-red-background-color has-background has-medium-font-size wp-block-paragraph" style="border-width:1px"><strong>固定された座標軸を、簡単かつ確実に作図したい</strong><br>　　──まずこれが、スクリプト作成を始めたきっかけです。</p>



<p class="wp-block-paragraph">また、スケッチ平面に対して高低差のある傾いた線を引きたい場合や、<br>平面からの異なる高さに円を描きたい場合なども、標準操作では少し手間がかかります。<br>前回作成したライブラリでは、直線や円といったシンプルな作図であれば、<span class="marker-under-blue">数値を引数として渡す</span>だけで描画できるところまでは実現しています。<br>ただし、実用面を考えると、やはり <span class="marker-under-red">GUI ダイアログ形式で数値入力できる仕様にしたい</span>というのが今回の取り組みです。</p>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-8" checked><label class="toc-title" for="toc-checkbox-8">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">Fusion API標準機能のコマンド UIでダイアログ仕様</a></li><li><a href="#toc2" tabindex="0">単純入力フォームに、tkinter を使ってみる</a><ol><li><a href="#toc3" tabindex="0">中心線作図スクリプト</a></li></ol></li><li><a href="#toc4" tabindex="0">表示されたボタンをクリックして、関数を実行するスクリプト</a><ol><li><a href="#toc5" tabindex="0">ボタンクリックで起動させる、tk.Button　の　command　オプション</a></li><li><a href="#toc6" tabindex="0">関数名の () の有無による違い</a><ol><li><a href="#toc7" tabindex="0">1. かっこがない場合 (cmd1)</a></li><li><a href="#toc8" tabindex="0">2. かっこがある場合 (cmd1())</a></li></ol></li><li><a href="#toc9" tabindex="0">lambda（ラムダ式）を使う</a></li></ol></li><li><a href="#toc10" tabindex="0">Tkinterは、Autodesk 非公式</a><ol><li><a href="#toc11" tabindex="0">Fusion API で、tkinter を使用する場合の注意点</a></li><li><a href="#toc12" tabindex="0">run(context) の context引数 は必須</a></li></ol></li><li><a href="#toc13" tabindex="0">数値入力ダイアログで、座標軸を作図するスクリプトをボタンで起動</a><ol><li><a href="#toc14" tabindex="0">サンプルスクリプトのダウンロードと使い方</a></li></ol></li><li><a href="#toc15" tabindex="0">第一弾、終了</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">Fusion API標準機能のコマンド UIでダイアログ仕様</span></h2>



<p class="wp-block-paragraph">Fusion API には、コマンドに付随する入力ダイアログ機能が標準で用意されており、テキストボックスやドロップダウンリスト、スライダーといった一般的な UI 要素を利用できます。<br>これらの UI 要素は <strong>Command Inputs </strong>オブジェクトを使って定義します。<br>コマンドが作成される際に呼び出される CommandCreated イベントハンドラ内で Command Inputs を作成し、コマンドの入力ダイアログに表示する入力フィールドを定義します。<br>その後、Execute イベントハンドラ内で、ユーザーがダイアログ上で入力した値を取得し、処理を実行します。<br>このように Fusion API のコマンドはイベント駆動で構成されており、各イベントハンドラを通して入力値を扱う必要があります。<br>とりあえずコード化してみましたが、初級者の私にとっては処理の流れを理解するのが難解でとりあえずネット情報やAIを参考に作成してみました<br>下記は、標準コマンドダイアログへの入力値を<a href="https://www.kazuban.com/blog/fusion-python-api/#toc16">上記で紹介している</a>「lib_2d.draw_center_line(x, y, z)スクリプトに取り込んでＸ，Ｙ，Ｚ座標軸線を作図させるスクリプトです</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="311" height="170" src="https://www.kazuban.com/blog/wp-content/uploads/2025/12/CommandDialog-e1767571988839.png" alt="" class="wp-image-11807" style="width:285px" srcset="https://www.kazuban.com/blog/wp-content/uploads/2025/12/CommandDialog-e1767571988839.png 311w, https://www.kazuban.com/blog/wp-content/uploads/2025/12/CommandDialog-e1767571988839-300x164.png 300w" sizes="(max-width: 311px) 100vw, 311px" /></figure>



<p class="wp-block-paragraph">class CommonAddinFramework:<br>　&#8221;&#8221;&#8221;<br>　Fusion 360 アドインの共通フレームワーククラス。<br>　ダイアログの表示、入力値の取得および指定された描画コールバック関数の実行を管理<br>　&#8221;&#8221;&#8221;<br>　def __init__(<br>　　self,<br>　　command_id: str,<br>　　button_name: str,<br>　　description: str,<br>　　input_defaults: dict,<br>　　drawing_callback,<br>　):<br><br>・・・・<br>・・・・</p>



<p class="wp-block-paragraph"><a href="https://www.kazuban.com/blog/fusion-api-commandhandler/" target="_blank">コード全体を表示</a></p>
</blockquote>



<h2 class="wp-block-heading"><span id="toc2">単純入力フォームに、tkinter を使ってみる</span></h2>



<p class="wp-block-paragraph">上記でFusion標準のコマンドUIを使って、寸法入力で座標軸線を作画できるようになりましたが、今後機能を増やしていくには、やはりイベント処理ではわかり辛く煩わしく感じますし、ネット上の情報も少ないです<br>そこで、Python標準のtkinterを使ってみました<br>tkinterはpython標準ライブラリなので、さすがにこちらは、情報豊富です</p>



<h3 class="wp-block-heading"><span id="toc3">中心線作図スクリプト</span></h3>



<p class="wp-block-paragraph">かなりAIに助けてもらいましたが<br><a href="https://www.kazuban.com/blog/fusion-python-api/#toc16">上記記事内</a>で作成した中心線スクリプトに入力数値を渡すダイアログをtkinterを利用して作成してみました。<br>最初にメッセージ表示の「label」を配置して、「entry」で設定値入力ボックスを配置<br>さらに、固定とコンストラクション設定用の「Checkbutton」を配置して作成ボタンで、作図させる仕様です</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="372" height="282" src="https://www.kazuban.com/blog/wp-content/uploads/2025/12/tkinter-center-line.png" alt="" class="wp-image-11809" style="width:285px" srcset="https://www.kazuban.com/blog/wp-content/uploads/2025/12/tkinter-center-line.png 372w, https://www.kazuban.com/blog/wp-content/uploads/2025/12/tkinter-center-line-300x227.png 300w" sizes="(max-width: 372px) 100vw, 372px" /></figure>



<p class="wp-block-paragraph"># &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br># ダイアログクラス <br># &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br>class DialogPanel(tk.Tk):<br>　def __init__(<br>　　self,<br>　　input_defaults: Dict[str, float],<br>　　construction,<br>　　fixed,<br>　):<br><br>・・・・<br>・・・・</p>



<p class="wp-block-paragraph"><a href="https://www.kazuban.com/blog/draw-centerline-by-tkinter/" target="_blank">コード全体を表示</a></p>
</blockquote>



<p class="wp-block-paragraph">この「DialogPanel」クラスをアレンジして、直線や円などを作図する入力ダイアログも追加作成していきます。<br>このスクリプトをFuisonの「スクリプトとアドイン」に登録すれば、作図スクリプトをダイレクト数値入力仕様で実行できるようになります。<br>私的には、FusionAPIのCommand Inputsよりもわかりやすいです。</p>



<h2 class="wp-block-heading"><span id="toc4">表示されたボタンをクリックして、関数を実行するスクリプト</span></h2>



<p class="wp-block-paragraph">いくつかコマンドダイアログを作成していくと、いちいち「スクリプトとアドイン」へ登録するのも面倒になってきます。<br>FusionAPIでもFusionタスクバーにコマンド実行プルダウンを追加できるようですが、これもまた敷居が高いです。<br>今回は、tkinterでメニュー用パネルを作成し、そのメニューボタンで作図スクリプトを起動できれば、メニューだけの登録で済みます。</p>



<h3 class="wp-block-heading"><span id="toc5">ボタンクリックで起動させる、tk.Button　の　command　オプション</span></h3>



<p class="wp-block-paragraph">ボタンクリックで関数を実行させるには「command」オプションに関数名を渡すと実行できます</p>



<pre class="wp-block-code"><code># 起動させたい関数
def <strong><span class="marker-red">cmd1()</span></strong>:
    print("Function is cmd1().")
・・・
・・・
# ボタンクリックで、「def cmd1()」関数を起動する
tk.Button(
        root,
        text="Execute_command01",
        <strong>command=<span class="marker-red">cmd1</span></strong>
)</code></pre>



<p class="wp-block-paragraph">ここで初心者の筆者が疑問に感じたのが、「<strong>command=cmd1</strong>」の書き方です<br>関数名は「cmd1()」なのに、「commandオプション」には&#8221;( )&#8221;が付かないようです<br>この関数名の&#8221;( )&#8221;の有無について、AIに聞いてみました</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<h3 class="wp-block-heading"><span id="toc6">関数名の <code>()</code> の有無による違い</span></h3>



<h4 class="wp-block-heading"><span id="toc7">1. かっこがない場合 (<code>cmd1</code>)</span></h4>



<p class="wp-block-paragraph">かっこがない場合、それは<strong>関数そのもの（オブジェクト）</strong> を指します。これは「<strong>関数というデータ</strong>」として扱われます。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>意味</strong></td><td><strong>関数そのものを指す（データ）</strong></td></tr></thead><tbody><tr><td>例</td><td><code>data = { "menu1": cmd1 }</code></td></tr><tr><td>目的</td><td>関数を<strong>変数に代入</strong>したり、<code>tk.Button</code> の <code>command</code> のように<strong>他の関数に引数として渡す</strong>とき。</td></tr><tr><td>動作</td><td><strong>処理はまだ実行されない</strong>。ただ関数の場所を渡すだけ。</td></tr></tbody></table></figure>



<h4 class="wp-block-heading"><span id="toc8">2. かっこがある場合 (<code>cmd1()</code>)</span></h4>



<p class="wp-block-paragraph">かっこがある場合、それは<strong>関数の実行（呼び出し）</strong> を意味します。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>意味</strong></td><td><strong>関数の処理を今すぐ実行する</strong></td></tr></thead><tbody><tr><td>例</td><td><code>cmd1()</code></td></tr><tr><td>目的</td><td>関数に書かれている<strong>処理をすぐに実行</strong>し、その<strong>戻り値（結果）</strong> を受け取るとき。</td></tr><tr><td>動作</td><td><strong>すぐに処理が実行される</strong>。もし戻り値があれば、その結果が残る。</td></tr></tbody></table></figure>
</blockquote>



<p class="wp-block-paragraph">なるほど～<br>&#8220;( )&#8221;がない場合には、C言語での<strong>ポインタ渡し</strong>のようなイメージですかね<br>&#8220;( )&#8221;を付けると、「すぐに実行される」との事なので、<br>クリック後実行させたい、「tk.Button」の「command」オプションには、使えないですね<br>したがってTkinterのcommand は、<strong><span class="marker-under-red">引数なし</span></strong><span class="marker-under-red">で呼び出せるものを要求</span>すると言うことになります<br>では、引数や戻り値を利用したい関数を実行するにはどうするか？</p>



<h3 class="wp-block-heading"><span id="toc9">lambda（ラムダ式）を使う</span></h3>



<p class="wp-block-paragraph">lambda は、短い無名関数（名前のない一時的な関数）を簡単に作るためのPythonの機能ですが、デフォルト引数を設定できるけど、実行時には引数なしで呼び出されるようです<br>したがって、「tk.Button」の「command」に利用できます<br>具体的には、<mark style="background-color:#fdf2f2" class="has-inline-color">「lambda 引数1,引数2…：引数を使った処理」</mark>のように記述します</p>



<pre class="wp-block-code"><code>def exec(function, msg):
    function(msg)
・・・・・・
・・・・・・
command = lambda <strong>msg</strong>="button click!", <strong>func</strong>=cmd1: exec(<strong>func, msg</strong>)</code></pre>



<p class="wp-block-paragraph">このように、関数：execに、func, msg　の引数を渡せば<br>「func名」の関数に「引数msg」を渡して実行できます<br>簡単な、サンプルコードを書いてみました</p>



<pre class="wp-block-code"><code>"""Execute a function on button click."""

import traceback
import adsk.core
import adsk.fusion

# import adsk.cam

import tkinter as tk


def disp_message(msg: str):
    app = adsk.core.Application.get()
    ui = app.userInterface
    ui.messageBox(f"{msg}")


def print_cmd1():
    disp_message("lambda is not used.")


def print_cmd2(msg: str):
    disp_message(msg)


def exec(function, msg):
    function(msg)


def run(context):
# def run():
    root = tk.Tk()
    label1 = tk.Label(
        root,
        text="Click the button.",
        bg="light cyan",
    )
    label1.pack()
    # ---------------------------------
    tk.Button(
        root,
        text="Execute1",
        command=<span class="bold-red">print_cmd1</span>,
    ).pack(side=tk.LEFT, padx=10, pady=10)
    # ---------------------------------
    tk.Button(
        root,
        text="Execute2",
        command=<span class="bold-red">lambda m="center button click!", f=print_cmd2: exec(f, m)</span>,
    ).pack(side=tk.LEFT, padx=10, pady=10)
    # ---------------------------------
    tk.Button(
        root,
        text="Execute3",
        command=<span class="bold-red">lambda m="right button click!", f=print_cmd2: exec(f, m)</span>,
    ).pack(side=tk.LEFT, padx=10, pady=10)
    root.mainloop()
</code></pre>



<p class="wp-block-paragraph">こんな感じで、「ボタン」を並べれば、ボタンクリック仕様のコマンド実行メニューが作成できそうです</p>



<h2 class="wp-block-heading"><span id="toc10">Tkinterは、Autodesk 非公式</span></h2>



<p class="wp-block-paragraph">「tk.Button」と「lambda」で、メニューダイアログが作れそうです<br><a href="#toc3">上記で紹介</a>した座標軸センターラインを作図するスクリプトを実行するダイアログを作成してみます<br>ところが、Tkinterの使用は、Autodeskは非公式のようなので注意が必要です</p>



<h3 class="wp-block-heading"><span id="toc11">Fusion API で、tkinter を使用する場合の注意点</span></h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">・Tkinterの使用は、Autodesk 非公式<br>・Tkinter が <code>root.mainloop()</code> で動作中は Fusion 本体の操作は一切できなくなる <br>・Mac + Tkinter は挙動が不安定なことがある<br>・Tkinterウィンドウを閉じた時に不安定になる場合がある<br>・最悪、タスクマネージャーでFusion 強制終了</p>
</blockquote>



<p class="wp-block-paragraph">やはり、Autodesk側としては、あまり推奨はしていないようです<br>常駐ツールやモーダルな本格的ダイアログはやめたほうがよさそうです<br>今回作成中も、閉じる時に「Script Error」が出たり、強制終了の必要に迫られたりしましたが、数値入力や条件入力の簡易パネルとして、<span class="marker-under-red">開いたら閉じて、Fusionに制御を返す</span>ような単純な処理であれば利用できると思っています。<br></p>



<h3 class="wp-block-heading"><span id="toc12">run(context) の context引数 は必須</span></h3>



<p class="wp-block-paragraph">python学習もかねて、いろいろ簡単なコードを書きました。<br>コードが悪いと、Fusionを強制終了させざるを得ない場合もありましたが、普通に問題なく動作しているのに、パネルの「×ボタン」で終了時に、Fusionのコマンドエリアに「SCRIPT ERROR」が出た事もありました。<br>これの原因究明には結構時間がかかりました。<br>上記のサンプルコードでも、run(context)の「context」は使っていないからと、<br>省略すると（「def run():」）「SCRIPT ERROR」になり、なにも動作しない状態になります<br>やはり、FusionAPIがどこかで使っていて、必須なようです<br>「×」での「SCRIPT ERROR」は終了時の警告のみなので、無視しようとも思いましたが、気味が悪いので、とりあえずAIにもいろいろも相談しましたが、的確な回答はもらえませんでした。<br>例えば下記コードで終了時に「SCRIPT ERROR」になります。<br>引数に「tk.Tk()型」を渡しました。結局、この引数が原因でした</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">def run1(root):<br>　&nbsp; &nbsp; label1 = tk.Label(root , text=&#8221;Click the button.&#8221;)<br>　　・・・・<br>　　・・・・<br><br>master = tk.Tk()<br>run1(master)</p>
</blockquote>



<p class="wp-block-paragraph">Fusionの「スクリプトとアドイン」で、「スクリプトまたはアドインを作成」を選択すると、自動的にサンプルスクリプトが作成されるので、そちらを参考にしてみました。<br>Fusionで自動作成された、run関数の中身は下記のようになっています</p>



<pre class="wp-block-code"><code>def run(_context: str):
    """This function is called by Fusion when the script is run."""

    try:
        # Your code goes here.
        ui.messageBox(f'"{app.activeDocument.name}" is the active Document.')
    except:  #pylint:disable=bare-except
        # Write the error message to the TEXT COMMANDS window.
        app.log(f'Failed:\n{traceback.format_exc()}')</code></pre>



<p class="wp-block-paragraph">引数は「_context: str」となっています。<br>以前のサンプルコードには、「str」のような型ヒントはなかったように記憶していますが<br>「str」なので引数の型は「文字列型」を期待しているようです。<br>このサンプルでも「_context」はどこにも使われていないように見えますが、やはりFusionAPI側では必須なのでしょう<br>ちなみにデフォルトでは「_context: str」と、型ヒントでは「文字列型」となっていますが、下記コードを追加して調べてみました</p>



<pre class="wp-block-code"><code>    ui.messageBox(f"type={type(_context)}")
    ui.messageBox(f"{_context}")</code></pre>



<p class="wp-block-paragraph">そのタイプと内容を表示させてみると</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">type=<strong>&lt;class &#8216;dict&#8217;&gt;</strong><br><strong>{&#8216;IsApplicationStartup&#8217;: False}</strong></p>
</blockquote>



<p class="wp-block-paragraph">このように、「辞書型」になっていました。<br>詳細はわかりませんが、メイン関数の第一引数はFusionが使うので、別の引数を使いたい場合には、追加の形をとったほうがよさそうです<br>この部分を変更すると正常に終了するようになりました。<br>pythonのこういった型のあいまいな部分にも、まだまだ慣れないです</p>



<h2 class="wp-block-heading"><span id="toc13">数値入力ダイアログで、座標軸を作図するスクリプトをボタンで起動</span></h2>



<p class="wp-block-paragraph">さて、上記で紹介した「中心線作図スクリプト」を、ボタンクリックで動作させるダイアログを作成してみようと思います。<br>ただし、このスクリプトは、<a href="https://www.kazuban.com/blog/fusion-python-api/">以前紹介した記事</a>内のライブラリ「<a href="https://www.kazuban.com/blog/fusion-python-api/#toc15">lib_util.py</a>」「<a href="https://www.kazuban.com/blog/fusion-python-api/#toc16">lib_2d.py</a>」を利用するので、もし試してみたい場合にはそちらも必要になります<br>下記に全部含まれたコードをダウンロードできるようにしておきますので、興味ある方がいらっしゃれば試してみてください。</p>



<pre class="wp-block-code"><code>"""Execute a function on button click."""

import adsk.core
import adsk.fusion
import os, sys, importlib, traceback
import tkinter as tk

import tkinter.font as tkFont
from typing import Optional, List, Dict, Any

current_dir = os.path.dirname(os.path.abspath(__file__))
script_dir = os.path.dirname(current_dir)  # C:\FusionAPI\Scripts
sys.path.append(script_dir)
# library import
"""
C:\FusionAPI\Scripts
│
├─library
│  ├─lib_util.py
│  ├─lib_2d.py
├─test
│  ├─menu.py (This script)
"""
from library import lib_util, lib_2d


##---------------------------
def disp_message(msg: str):
    lib_util.disp_message(msg)


# ------------------------------------------------------------------
# ダイアログクラス
# ------------------------------------------------------------------
class DialogPanel(tk.Tk):
    """センターライン作画ダイアログ"""

    def __init__(
        self,
        input_defaults: Dict&#91;str, float],
        construction,
        fixed,
    ):
        super().__init__()
        # self.my_font = None
        self.input_defaults = input_defaults
        self.x_width: float = 0.0
        self.y_width: float = 0.0
        self.z_width: float = 0.0
        self.construction: bool = construction
        self.fixed: bool = fixed
        self.widths: dict&#91;str, tk.DoubleVar] = {}
        self._create_widgets()

    def _simple_frame(self, **kwargs) -&gt; tk.Frame:
        # Fontインスタンスを作成
        self.my_font = tkFont.Font(family="Arial", size=10, weight="normal")
        """単純フレームを作成し、ウィンドウ全体に展開"""
        master = self
        frame = tk.Frame(master, **kwargs)
        master.title("Center Line")
        frame.pack(fill="both", expand=True, padx=5, pady=5)
        return frame

    def _create_widgets(self):
        """全てのUI要素を作成"""
        # 全体を包む単一のフレーム
        self.main_frame = self._simple_frame(relief="ridge", bd=5)

        # ------------------
        # 0. トップメッセージ
        # ------------------
        row_idx = 0
        top_frame = tk.Frame(self.main_frame)
        top_frame.grid(row=row_idx, column=0, columnspan=3, pady=10)
        tk.Label(
            top_frame,
            text="各軸の長さを指定してください。\n作成したくない軸は「0.0」にしてください",
            bg="light cyan",
            font=self.my_font,
        ).pack()
        # ------------------
        # 1～3 各軸幅入力ボックス
        # ------------------

        row_idx += 1
        # 事前設定のラベルとデフォルト値
        for label, default in self.input_defaults.items():
            tk.Label(
                self.main_frame,
                text=label,
                font=self.my_font,
            ).grid(
                row=row_idx,
                column=0,
                sticky="e",
            )
            var = tk.DoubleVar(value=default)
            ent = tk.Entry(
                self.main_frame,
                font=self.my_font,
                textvariable=var,
                width=10,
                bg="lightyellow",
                # bg="ivory",
            )
            ent.grid(row=row_idx, column=1)
            self.widths&#91;label] = var
            row_idx += 1
        # ------------------
        # 4. 要素固定チェック
        # ------------------
        row_idx += 1
        # self.fixed_check = tk.BooleanVar(value=True)
        self.fixed_check = tk.BooleanVar(value=self.fixed)
        check_button = tk.Checkbutton(
            self.main_frame,
            text="要素固定",
            variable=self.fixed_check,
            font=self.my_font,
        )
        check_button.grid(row=row_idx, column=0, padx=5, pady=5, sticky="w")
        # self.construction_check = tk.BooleanVar(value=True)
        self.construction_check = tk.BooleanVar(value=self.construction)
        check_button = tk.Checkbutton(
            self.main_frame,
            text="コンストラクション",
            variable=self.construction_check,
            font=self.my_font,
        )
        check_button.grid(row=row_idx, column=1, padx=5, pady=5, sticky="w")

        # ------------------
        # 5. 最終確定ボタン
        # ------------------
        row_idx += 1
        # ボタンを格納するボトムフレーム
        bottom_frame = tk.Frame(self.main_frame)
        bottom_frame.grid(row=row_idx, column=0, columnspan=3, pady=10)

        tk.Button(
            bottom_frame, text="作成実行", font=self.my_font, command=self.get_data
        ).pack(side=tk.LEFT, padx=10)
        tk.Button(
            bottom_frame, text="閉じる", font=self.my_font, command=self.destroy
        ).pack(side=tk.LEFT, padx=10)

    def get_data(self):
        """入力データを取り出す"""
        v: List = &#91;]
        for value in self.widths.values():
            v.append(value.get())
        self.x_width = float(v&#91;0])
        self.y_width = float(v&#91;1])
        self.z_width = float(v&#91;2])
        self.fixed = self.fixed_check.get()
        self.construction = self.construction_check.get()
        self.destroy()


##--------------------------------------------------------------
##--------------------------------------------------------------
def diarog_test(master):
    """センターライン作画"""
    if master:
        master.quit()  # mainloop を終了させる
        master.destroy()
    input_defaults = {
        "X軸長さ": 50.0,
        "Y軸長さ": 50.0,
        "Z軸長さ": 10.0,
    }
    # 線種指定
    construction = True
    fixed = True

    app = DialogPanel(input_defaults, construction, fixed)
    app.mainloop()
    wx = app.x_width
    wy = app.y_width
    wz = app.z_width
    construction = app.construction
    fixed = app.fixed
    try:
        lib_2d.draw_center_line(wx, wy, wz, construction, fixed)
    except:
        disp_message("Failed:\n{}".format(traceback.format_exc()))


# ---- Action command after button click ----------


def print_cmd1():
    disp_message("lambda is not used.")


def print_cmd2(msg: str):
    disp_message(msg)


def exec(function, msg):
    function(msg)


def on_closing(root):
    """Processing when the window's 'x' button is pressed"""
    disp_message("I'll close now!")
    root.quit()  # Terminate the mainloop
    root.destroy()  # Releases window resources.


def button(root: tk.Tk):
    # Window close action
    root.protocol("WM_DELETE_WINDOW", lambda: on_closing(root))
    label1 = tk.Label(root, text="Click the button you like.", bg="light cyan")
    label1.pack()
    tk.Button(root, text="Message1", command=print_cmd1).pack(
        side=tk.LEFT, padx=10, pady=10
    )
    tk.Button(
        root,
        text="Message2",
        command=lambda m="Lambda specification!", f=print_cmd2: exec(f, m),
    ).pack(side=tk.LEFT, padx=10, pady=10)
    tk.Button(
        root,
        text="Draw center line",
        command=lambda tk=root, f=diarog_test: exec(f, tk),
    ).pack(side=tk.LEFT, padx=10, pady=10)
    root.mainloop()


def run(context: dict):  # {'IsApplicationStartup': False}
    root = tk.Tk()
    root.attributes("-topmost", True)  # Bring Window To Top
    button(root)
</code></pre>



<h3 class="wp-block-heading"><span id="toc14">サンプルスクリプトのダウンロードと使い方</span></h3>



<p class="wp-block-paragraph">ダウンロードと使用方法は下記を参考にしてください<br>この例では、展開されたトップフォルダ「FusinAPI_kazuban」を「Cドライブ」の直下に、コピーする方法で説明していますが、任意の場所でかまいません<br>ただし、<span class="marker-under">Fusionが立ち上がった状態</span>では、キャッシュの影響で「library」内のスクリプトがうまく読み込めない事があります<br><span class="marker-under-red">コピー後に、Fusionを起動する</span>方がトラブル少ないです。<br>そのトップフォルダ下の「Scripts」、その下の「library」「menyu01」内のスクリプトを使用します<br>全ての使用ライブラリも含めたZIPファイルは下記からのダウンロードできます</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="348" height="125" src="https://www.kazuban.com/blog/wp-content/uploads/2026/01/python-api-tkinter01.png" alt="" class="wp-image-11941" srcset="https://www.kazuban.com/blog/wp-content/uploads/2026/01/python-api-tkinter01.png 348w, https://www.kazuban.com/blog/wp-content/uploads/2026/01/python-api-tkinter01-300x108.png 300w" sizes="(max-width: 348px) 100vw, 348px" /></figure>



<div class="wp-block-file"><a id="wp-block-file--media-11c24981-b4de-424e-be88-7ef09c825cf3" href="https://www.kazuban.com/blog/wp-content/uploads/2026/01/FusinAPI_kazuban.zip">FusinAPI_kazuban</a><a href="https://www.kazuban.com/blog/wp-content/uploads/2026/01/FusinAPI_kazuban.zip" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-11c24981-b4de-424e-be88-7ef09c825cf3">ダウンロード</a></div>



<pre class="wp-block-preformatted">C:\FusinAPI_kazuban<br>└─Scripts<br>    ├─library<br>        └─lib_2d.py<br>        └─lib_util.py<br>    └─menyu01<br>        └─menu.py</pre>



<p class="wp-block-paragraph">・ダウンロード後展開した「FusinAPI_kazuban」を適当なフォルダへコピー<br>・Fusionの「スクリプトとアドイン」から「menyu01」を選択する<br>・正常に登録されると、スクリプトが実行できます</p>



<figure class="wp-block-video"><video height="1028" style="aspect-ratio: 1496 / 1028;" width="1496" controls src="https://www.kazuban.com/blog/wp-content/uploads/2026/01/python-api-tkinter01.mp4"></video></figure>
</blockquote>



<h2 class="wp-block-heading"><span id="toc15">第一弾、終了</span></h2>



<p class="wp-block-paragraph">とりあえず、Autodesk Fusion からtkinterオブジェクトのパネルを表示し、ボタンに割り当てられたスクリプト動作をさせる事ができました。<br>数値入力用ボタンでは、tkinterへの入力値をFusionAPIに渡し、作図させる事ができるようになりました<br>次回は、もう少し作図スクリプトとメニューを充実させていきたいと思います</p>





<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		<enclosure url="https://www.kazuban.com/blog/wp-content/uploads/2026/01/python-api-tkinter01.mp4" length="9464158" type="video/mp4" />

			</item>
		<item>
		<title>Fusion360  Python API 再挑戦！AIの力を借りて、sketchなど基本ライブラリを作ってみた。</title>
		<link>https://www.kazuban.com/blog/fusion-python-api/</link>
		
		<dc:creator><![CDATA[kazuban]]></dc:creator>
		<pubDate>Tue, 08 Jul 2025 20:01:00 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Fusion360]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[AIとのやり取り]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://www.kazuban.com/blog/?p=11250</guid>

					<description><![CDATA[数年前、Fusion360のPython APIに少しだけ触れたことがあります。当時はPython自体が初めてで、構文の違いに戸惑いました。C言語に慣れていた私には、インデントでブロックを作る点や、変数・関数に型の宣言が [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">数年前、Fusion360のPython APIに少しだけ触れたことがあります。<br>当時はPython自体が初めてで、構文の違いに戸惑いました。<br>C言語に慣れていた私には、インデントでブロックを作る点や、変数・関数に型の宣言が不要な点など、なかなか馴染めませんでした。<br>さらに、Fusion独自のオブジェクトや関数の使い方を調べる必要があり、作業のハードルは思った以上でした。<br><a href="https://qiita.com/reisyu/items/84aa97117439e4962bbf">こちらのブログ記事</a>や<a href="https://kantoku.hatenablog.com/archive/category/Fusion360API?page=20">「Kantoku」さんのサイト</a>を参考にしながら少しだけ進めてみたのですが、残念ながら長続きせず中断してしまいました。</p>



<p class="wp-block-paragraph">ところが昨年、AI（生成AI）が大きく注目されるようになり、「これを使ってみるか？」と再び興味がわきました。<br>試しにFusion向けのコードをAIに聞いてみると、実際に動作するスクリプトを提案してくれて、少しやる気が復活…<br>しかしそれも一時的で、またもや放置状態に。</p>



<figure class="wp-block-embed is-type-wp-embed"><div class="wp-block-embed__wrapper">

<a href="https://www.kazuban.com/blog/generative-ai-for-fusion360/" title="話題の『生成Ai』に、Fusion360のPythonスクリプトをきいてみた" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://www.kazuban.com/blog/wp-content/uploads/2024/01/generative-ai-160x90.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://www.kazuban.com/blog/wp-content/uploads/2024/01/generative-ai-160x90.jpg 160w, https://www.kazuban.com/blog/wp-content/uploads/2024/01/generative-ai-120x68.jpg 120w, https://www.kazuban.com/blog/wp-content/uploads/2024/01/generative-ai-320x180.jpg 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">話題の『生成Ai』に、Fusion360のPythonスクリプトをきいてみた</div><div class="blogcard-snippet internal-blogcard-snippet">最近『生成Ai』を触り始めました。今までの、検索に比べても、非常に便利です。できる事の幅が広すぎて、ついていけませんが、プログラムコードも出力してくれるようです。いままで手を付けていなかった、Fusion360のPythonスクリプトを質問してみました。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://www.kazuban.com/blog" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">www.kazuban.com</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.01.27</div></div></div></div></a>
</div></figure>



<p class="wp-block-paragraph">そして今回！<br>AIもさらに進化してきた今こそ、もう一度挑戦してみようと思い立ちました。<br>本記事では、Fusion360 Python API に再び取り組み始めた記録と、コーディングへのAIの活用事例をレポートしています。<br>例題として、Fusion APIの基本ライブラリを作成しましたので、利用できそうであれば、利用していただければ幸いです。</p>



<p class="wp-block-paragraph">なお、より高度なスクリプトや実践的な例に興味がある方は、<a href="https://kantoku.hatenablog.com/archive/category/Fusion360API?page=20">「Kantoku」さんのサイト</a>に素晴らしい資料が公開されていますので、ぜひチェックしてみてください。</p>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-10" checked><label class="toc-title" for="toc-checkbox-10">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">今回の目標：スケッチ関連の基本ライブラリを作る</a></li><li><a href="#toc2" tabindex="0">Aiの実力を試してみる</a><ol><li><a href="#toc3" tabindex="0">fusionのpython API で直線を引くコード</a><ol><li><a href="#toc4" tabindex="0">ローカルLLM</a></li><li><a href="#toc5" tabindex="0">オンラインLLM</a></li></ol></li><li><a href="#toc6" tabindex="0">コンポネントやスケッチのアクティブな状態を把握</a><ol><li><a href="#toc7" tabindex="0">現状がスケッチモードかどうかの判定</a></li></ol></li></ol></li><li><a href="#toc8" tabindex="0">python特有な構文</a></li><li><a href="#toc9" tabindex="0">Fusion スクリプトをライブラリ化する</a><ol><li><a href="#toc10" tabindex="0">ライブラリの登録場所とpythonでの実装方法</a></li><li><a href="#toc11" tabindex="0">実行スクリプトと同じレベルのスクリプトをインポートするには？</a></li></ol></li><li><a href="#toc12" tabindex="0">ライブラリ利用方法</a></li><li><a href="#toc13" tabindex="0">ライブラリを利用して、X,Y,Zの座標軸にセンターラインを描く</a><ol><ol><li><a href="#toc14" tabindex="0">CenterLine.py</a></li><li><a href="#toc15" tabindex="0">lib_util.py</a></li><li><a href="#toc16" tabindex="0">lib_2d.py</a></li></ol></li></ol></li><li><a href="#toc17" tabindex="0">注意点</a></li><li><a href="#toc18" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">今回の目標：スケッチ関連の基本ライブラリを作る</span></h2>



<p class="wp-block-paragraph">Python言語は、ほとんど初心者ですが、ネット情報やAiを参考にコードをコピペするだけでは、なかなか覚えられないと思っています。<br>そこで、基本的なコードをライブラリ化する事で、少しは理解も深まるかと思い、まずはスケッチ周りの基本コードをライブラリ化してみようと思います</p>



<h2 class="wp-block-heading"><span id="toc2">Aiの実力を試してみる</span></h2>



<p class="wp-block-paragraph">さっそく、何種類かのLLMに質問してみました。</p>



<h3 class="wp-block-heading"><span id="toc3">fusionのpython API で直線を引くコード</span></h3>



<h4 class="wp-block-heading"><span id="toc4">ローカルLLM</span></h4>



<p class="wp-block-paragraph">ローカルの場合、私の環境では、レスポンス的に30bぐらいが実用できる限界です。<br>そこで、「gemma-3-27b」「qwen3-32b」で試してみます</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">「fusionのpython API で直線を引くコードをだして」</p>
</blockquote>



<p class="wp-block-paragraph">最初に、「import adsk.core, adsk.fusion, traceback」など<span class="marker-under">Fusion特有のパッケージをインポート</span>しするコードを出してくれるので、なかなかいいな！と思っていましたが、実際にFusionで実行してみても正常動作しませんでした。<br>特に、CAD画面上にメッセージを出力する場合、「ui.messageBox」を利用しますが、一般的なpythonの「print」文を使ったりしています。<br>また、私の環境で30bクラスのLLMでは、<span class="marker-under-blue">回答に５分以上</span>かかりました。<br>文章をまとめたり、翻訳したりの場合では、8bクラスでもいい回答をもらえますが、Fusion API のPython場合はちょっとマイナーなのかもしれません<br>参考にはなると思いますが、<span class="marker-under-red">私</span><span class="marker-under-red">の</span><span class="marker-under-red">環境</span><span class="marker-under-red">では</span><span class="marker-under-red">ちょっとレスポンスが悪いです</span>。</p>



<h4 class="wp-block-heading"><span id="toc5">オンラインLLM</span></h4>



<p class="wp-block-paragraph">次に、オンラインの「chatGPT」と「gemini」で試してみました。<br><span class="marker-under">「chatGPT」も「gemini」も、正常に動作しました</span>。<br>ただし、ログインしないと、会話履歴や共有できないので、ログインしたほうがいいと思います。<br>制限がある場合がありますが、そこそこ無料利用できます。<br>やはり、さすがです。回答レスポンスも早いです。<br>今回の質問では、<a href="https://www.kazuban.com/blog/generative-ai-for-fusion360/#toc6">一年前に、出してくれたコードとほとんど同じコードをだしてくれました。</a><br>一年前は、「bard(gemini)」のコードは、正常動作しないコードでしたが、現在の「gemini」は問題ないコードを出してくれます。<br>個人的は、ローカルLLMを使いたい気持ちがあるのですが、開発作業では、やはりレスポンスは重要なので、今後の学習はオンラインLLMを利用しようと思います。<br>まずは「Gemini 2.5Flash」を利用してみて、いい回答が出なかった場合には、「chatGPT」や「Gemini 2.5Pro」を使おうと思います</p>



<h3 class="wp-block-heading"><span id="toc6">コンポネントやスケッチのアクティブな状態を把握</span></h3>



<p class="wp-block-paragraph"><a href="https://www.kazuban.com/blog/generative-ai-for-fusion360/#toc6">上記の直線を描くサンプルコード</a>では、ルートコンポネントに新しいスケッチを作成し、そのスケッチに直線を引いています。<br>もう少し、実践的な動作にしたいです。</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<ul class="wp-block-list">
<li>スケッチモードであれば、そのスケッチに・・</li>



<li>スケッチモードでない場合、ルートにこだわらず、アクティブなコンポネントに新しいスケッチを作成しそのスケッチに・・</li>
</ul>
</blockquote>



<p class="wp-block-paragraph">これを実現させるには、まず<span class="marker-under">現状のアクティヴな状態を把握する</span>必要があります<br>アクティブなコンポーネントを見つける関数はすぐ見つかりましたが、<span class="marker-under-red">スケッチのモード判定方法はなかなか見つか</span><span class="marker-under-red">らず</span>Aiのお陰でどうにかなりそうです。<br>こういった汎用的だけど苦労した処理を、ライブラリ化しておくと、後々便利だと思います</p>



<h4 class="wp-block-heading"><span id="toc7">現状がスケッチモードかどうかの判定</span></h4>



<p class="wp-block-paragraph">何度かgemini に聞いてみたところ、「<strong>activeEditObject」</strong>「<strong>activeEnvironment</strong>」を使用する方法があるとの回答をもらいました。<br>ただし、Ai としては、<span class="marker-under-red">「<strong>activeEditObject</strong>」を推奨</span>するとの事でした</p>



<pre class="wp-block-code has-cocoon-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-3"><code>import adsk.core
import adsk.fusion

def is_sketch_mode_active():
    """
    現在スケッチモード（いずれかのスケッチが編集中）かどうかを判定します。

    Returns:
        bool: スケッチモードであれば <strong>True</strong>、そうでなければ <strong>False</strong>。
        adsk.fusion.Sketch: アクティブなスケッチオブジェクト（スケッチモードの場合）。
    """
    try:
        app = adsk.core.Application.get()
        
        # 現在編集中のオブジェクトを取得
        active_object = app.activeEditObject

        # 編集中のオブジェクトがスケッチ（Sketch）であるかを確認
        if active_object and <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-yellow-color">isinstance(active_object, adsk.fusion.Sketch):</mark>
            return <strong>True</strong>, active_object
        else:
            return <strong>False</strong>, None

    except:
        return False, None

# --- 実行例 ---
def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface

        is_active, active_sketch = is_sketch_mode_active()

        if is_active:
            ui.messageBox(f'はい、現在スケッチモードです。\nアクティブなスケッチ: {active_sketch.name}')
        else:
            ui.messageBox('いいえ、現在スケッチモードではありません。')

    except:
        if ui:
            ui.messageBox('エラーが発生しました。')</code></pre>



<p class="wp-block-paragraph">判定で、「<span class="marker-under-red">isinstance()</span>」関数を使っています。<br>これは、自力では、なかなか探せなかったと思います。恐るべし、Aiです。</p>



<h2 class="wp-block-heading"><span id="toc8">python特有な構文</span></h2>



<p class="wp-block-paragraph">Aiが出してくれた、サンプルコードを見ると、C言語とは違う書き方が結構出てきます<br>例えば</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">return<strong> True , active_object</strong></p>
</blockquote>



<p class="wp-block-paragraph">のように、複数変数を返す事ができて、取り出しは、下記のように「,」で区切って利用できるのですね</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>is_active , active_sketch</strong> = is_sketch_mode_active()</p>
</blockquote>



<p class="wp-block-paragraph">C++言語では、最近ではstd::tupleが利用できるみたいですが、それを知らない私は、classを使ったりしていますが、こちらのほうが、面倒ないですね。<br>「if文」も「<strong>三項演算子</strong>」と呼ばれている構文が結構使われていました。</p>



<pre class="wp-block-code has-cocoon-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-4"><code>design = get_design()
return <strong><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-yellow-color">design.activeComponent if design else None</mark></strong></code></pre>



<p class="wp-block-paragraph">C言語にも「三項演算子」はありますが、if文のほうが、分かりやすいかも・・<br>配列系も、多種類があるようで、Aiが出してくれたサンプルでも結構多用しています</p>



<pre class="wp-block-code"><code>plane = plane.lower()
planes_map = {
    "xy": component.xYConstructionPlane,
    "xz": component.xZConstructionPlane,
    "yz": component.yZConstructionPlane
}   
base_plane = planes_map.get(plane)</code></pre>



<p class="wp-block-paragraph">この「<strong>.get(plane)</strong>」はなんだ？<br>と思いましたが、これもAiに聞くと、すぐに説明してくれました。<br><strong>planes_map[plane]</strong>でもアクセスできるようですが、<span class="marker-under-red"><strong>get()</strong>を使うと<strong>plane</strong>が存在しない場合安全に</span>デフォルト値（<code><strong>None</strong></code>または指定した値）を返してくれるようです。<br>本当にすぐに教えてくれるので、私のような独学の場合、参考書などをめくるよりも、言語の理解は数段速くなるでしょうね～</p>



<h2 class="wp-block-heading"><span id="toc9">Fusion スクリプトをライブラリ化する</span></h2>



<p class="wp-block-paragraph">Fusion では、「ユーティリティ」⇒「アドイン」⇒「スクリプトとアドイン」⇒「+」で新規にスクリプトを作成できます</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="754" height="572" src="https://www.kazuban.com/blog/wp-content/uploads/2025/07/NewScript.png" alt="" class="wp-image-11300" srcset="https://www.kazuban.com/blog/wp-content/uploads/2025/07/NewScript.png 754w, https://www.kazuban.com/blog/wp-content/uploads/2025/07/NewScript-500x379.png 500w, https://www.kazuban.com/blog/wp-content/uploads/2025/07/NewScript-300x228.png 300w" sizes="(max-width: 754px) 100vw, 754px" /></figure>



<p class="wp-block-paragraph">このダイアログの「<strong>フォルダの場所</strong>」に「<strong>名前</strong>」に入力のフォルダを作成し、その中に「<strong>名前.py</strong>」で実行スクリプトが作成されます。<br>「フォルダの場所」はデフォルトでは、かなり深いので、私は「D:\Fusion360\Scripts」のようにシンプルな場所に変更しています。<br>また、この場所は、<span class="marker-under">「基本設定」⇒「一般」⇒「API」</span>でデフォルトを変更できます<br>ただし、ここでの設定箇所に<span class="marker-under-red">「Scripts」は自動作成</span>されるので、<span class="marker-under-red">「D:\Fusion360」</span>になります</p>



<p class="wp-block-paragraph">Fusionスクリプトは、Fusionオブジェクトモデルを介して、利用したいオブジェクトのコマンドを記述します。<br>したがって、スクリプトを作成するには、各オブジェクトの情報が必要となり、かなり複雑です。</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="677" height="437" src="https://www.kazuban.com/blog/wp-content/uploads/2025/07/Sketch-2.png" alt="" class="wp-image-11332" srcset="https://www.kazuban.com/blog/wp-content/uploads/2025/07/Sketch-2.png 677w, https://www.kazuban.com/blog/wp-content/uploads/2025/07/Sketch-2-500x323.png 500w, https://www.kazuban.com/blog/wp-content/uploads/2025/07/Sketch-2-300x194.png 300w" sizes="(max-width: 677px) 100vw, 677px" /></figure>



<p class="wp-block-paragraph"><br>今回は、Pythonの学習も兼ねて、Fusionのスケッチ関連オブジェクトをカプセル化したライブラリを作成したいと思います。</p>



<h3 class="wp-block-heading"><span id="toc10">ライブラリの登録場所とpythonでの実装方法</span></h3>



<p class="wp-block-paragraph">ライブラリフォルダは、Fusionが自動作成する、「Scripts」内の自作スクリプトと同じレベルに登録したいと思います</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">D:\Fusion360\Scripts<br>├── 新規スクリプト<br>├── CenterLine # 自作スクリプト<br>│ └── CenterLine.py # X,Y,Zの軸のセンターラインを作成する<br>│<br>├── library # 作成ライブラリ登録フォルダ<br>│ ├── <em>_init_</em>.py # 空ファイル（必要らしい）<br>│ ├── lib_util.py # Component &amp; Sketch 関連関数<br>│ └── lib_2d.py # 点や直線を作成（今後、円、円弧なども追加予定）<br></p>
</blockquote>



<p class="wp-block-paragraph">私の環境では、このようなイメージです。<br>「library」フォルダ内に「lib_util.py」「lib_2d.py」スクリプトを作成<br>「lib_util.py」は、Component や sketch を提供する基本関数を記述します<br>「lib_2d.py」は、点や直線を扱う関数を作成しますが、<span class="marker-under">「<strong>lib_util.py</strong>」の関数も利用します</span><br>今回はこの二つのライブラリを利用して、 X,Y,Zの軸のセンターラインを作成する「CenterLine /CenterLine.py」スクリプトを作成します</p>



<h3 class="wp-block-heading"><span id="toc11">実行スクリプトと同じレベルのスクリプトをインポートするには？</span></h3>



<p class="wp-block-paragraph">インポートするコードもわからないので、さっそくAiに聞いてみました<br>上記の構造をAiに渡して、実行スクリプト「CenterLine.py」から「lib_util.py」の関数を利用するコードを聞いてみました<br>この場合、正確なディレクトリ構造を取得する事が必要だと言うことで下記コードを教えてもらいました。</p>



<pre class="wp-block-code has-cocoon-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-5"><code>current_dir = os.path.dirname(os.path.abspath(__file__))
script_dir = os.path.dirname(current_dir)</code></pre>



<p class="wp-block-paragraph">この構成はよくライブラリや設定ファイルを<span class="marker-under">相対パスで読み込むときの定番のコード</span>のようです<br>もう少し、詳しく説明してもらいました。</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">_file_：現在実行中のPythonスクリプトのファイルパス<br>os.path.abspath(__file__)：絶対パスに変換<br>os.path.dirname(…)：そのファイルが属するディレクトリを取得<br><br>D:/Fusion360/Scripts/<br>├── library/<br>│ └── __init__.py # モジュールの初期化用<br>│ └── lib_util.py<br>│ └── lib_2d.py<br>├── CenterLine/<br>│ └── CenterLine.py ← 実行スクリプト</p>



<p class="wp-block-paragraph">__file__ → &#8220;./CenterLine/CenterLine.py&#8221;<br>abspath(__file__) → &#8220;D:/Fusion360/Scripts/library/CenterLine/CenterLine.py&#8221;<br>current_dir → &#8220;D:/Fusion360/Scripts/library/CenterLine&#8221;<br>script_dir → &#8220;D:/Fusion360/Scripts/library&#8221;</p>
</blockquote>



<p class="wp-block-paragraph">このコードで、ライブラリのディレクトリを取り出し、<br>「sys.path.append(script_dir)」でpythonが内部でモジュール検索時に、指定ディレクトリを追加するの意味のようです<br>この設定後に、「from library import lib_util」コードで「library」ディレクトリ内の「lib_util.py」内の関数を使用できるようになります<br>具体的には、下記になります</p>



<pre class="wp-block-code has-cocoon-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-6"><code>import os, sys

current_dir = os.path.dirname(os.path.abspath(__file__))
script_dir = os.path.dirname(current_dir)
sys.path.append(script_dir)
from <strong>library </strong>import <strong>lib_util</strong></code></pre>



<p class="wp-block-paragraph">これで、新規作成したスクリプトに、このコードを追加すると、「lib_util」内の関数が使えます<br>さらに「lib_2d.py」ライブラリも、「lib_util.py」の関数も利用しますが、こちらは、<span class="marker-under">「lib_util.py」と同じディレクトリ内</span>なので、「script_dir = os.path.dirname(current_dir)」のコードは<span class="marker-under-red">不要</span>になりますね</p>



<pre class="wp-block-code has-cocoon-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-7"><code>import os, sys
current_dir = os.path.dirname(os.path.abspath(__file__))
<s><strong>#</strong> script_dir = os.path.dirname(current_dir)</s>
sys.path.append(current_dir)
import lib_util
</code></pre>



<p class="wp-block-paragraph">実際には結構時間がかかったのですが、これで、やっとライブラリが使えるようになりました。<br>本当、Ai様様です。<br>Aiの進歩で、コーディングの勉強は不要だとの意見もありますが、やっぱりコードの意味の理解は必要だと思います。<br>たぶん、Aiもそう思っているのでしょう！詳しいコメントを日本語で追記してくれます。<br>「あなたの言葉でコメントつけるから、覚えてね！」と言ってる気がします。<br>Ai利用でプログラミングの学習速度は、以前よりも圧倒的に速くなると思います</p>



<h2 class="wp-block-heading"><span id="toc12">ライブラリ利用方法</span></h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">./Scripts/<br>├── 新規スクリプト/ # &lt;&#8212;&#8212;&#8211; Fusion ダイアログで作成<br>│ └── 新規スクリプト.py<br>├── library/ #&lt;&#8212;&#8212;&#8212; Scripts/ 直下に作成<br>│ └── __init__.py # &lt;&#8212;&#8211; 空ファイル追加作成、モジュールの初期化用<br>│ └── lib_util.py # &lt;&#8212;&#8212;- ライブラリファイル<br>│ └── lib_2d.py # &lt;&#8212;&#8212;- ライブラリファイル<br>└── CenterLine/ # &lt;&#8212;&#8212;- 自作スクリプト用<br>│ └── CenterLine.py # &lt;&#8212;&#8212;- 自作スクリプトファイル<br>└─────── </p>
</blockquote>



<p class="wp-block-paragraph">イメージ的には、このようになります。<br>Fusionで「スクリプトまたはアドイン作成」を実行すると、設定ダイアログが表示され、設定した「フォルダの場所」へ設定した名前のフォルダが自動作成され、さらにその中に、設定した名前.py の実行ファイルが作成されます。</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="558" height="224" src="https://www.kazuban.com/blog/wp-content/uploads/2025/07/add-ins.png" alt="" class="wp-image-11358" srcset="https://www.kazuban.com/blog/wp-content/uploads/2025/07/add-ins.png 558w, https://www.kazuban.com/blog/wp-content/uploads/2025/07/add-ins-500x201.png 500w, https://www.kazuban.com/blog/wp-content/uploads/2025/07/add-ins-300x120.png 300w" sizes="(max-width: 558px) 100vw, 558px" /></figure>



<p class="wp-block-paragraph">今回紹介のライブラリは、Fusionで設定した「フォルダの場所」の直下に「library」の名前でフォルダを作成し、さらに「library」の直下に、「__init__.py」「lib_util.py」「lib_2d.py」を作成します<br>「__init__.py」は、空ファイルですが、Aiが言うには、ライブラリを利用する際必要みたいです。<br>「lib_util.py」「lib_2d.py」も一旦空ファイルを作っておいて、下記コードをコピペして保存します</p>



<h2 class="wp-block-heading"><span id="toc13">ライブラリを利用して、X,Y,Zの座標軸にセンターラインを描く</span></h2>



<p class="wp-block-paragraph">まずは、Fusion 「スクリプトとアドイン」で、新規スクリプトを作成します<br>ここでは「CenterLine」という名前にしました。<br>これで、「./Scripts」ディレクトリ内に、「CenterLine/CenterLine.py」が作成されています。<br>CenterLine.pyファイルの内容を、下記コードで上書きして保存します</p>



<h4 class="wp-block-heading"><span id="toc14">CenterLine.py</span></h4>



<pre class="wp-block-code has-cocoon-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-8"><code>"""This file acts as the main module for this script."""

import traceback
import adsk.core
import adsk.fusion
# import adsk.cam

import os, sys, importlib
#library import
current_dir = os.path.dirname(os.path.abspath(__file__))
script_dir = os.path.dirname(current_dir)
sys.path.append(script_dir)
from library import lib_util,lib_2d

def run(context):
    try:
        lib_2d.draw_center_line(100,100,100)
 
    except:
        lib_util.disp_message('Failed:\n{}'.format(traceback.format_exc()))
</code></pre>



<p class="wp-block-paragraph">下記が、ライブラリ用スクリプトファイルです</p>



<h4 class="wp-block-heading"><span id="toc15">lib_util.py</span></h4>



<pre class="wp-block-code has-cocoon-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-9"><code>import adsk.core, adsk.fusion, adsk.cam, traceback
from typing import Tuple, Optional

#このライブラリは
#Fusionが作成するスクリプトと同じディレクトリに置かれる事を想定している
#使用する場合には、下記コードにより読み込みパスを追加する
"""
import os, sys, importlib
current_dir = os.path.dirname(os.path.abspath(__file__))
script_dir = os.path.dirname(current_dir)
sys.path.append(script_dir)
from library import lib_util
"""
# ---------------------
## Get Fusion object
# ---------------------
def get_app():
    return adsk.core.Application.get()
def get_design():
    app = get_app() 
    return adsk.fusion.Design.cast(app.activeProduct)
def get_ui():
    app = get_app() 
    return app.userInterface

# ---------------------
## メッセージ表示
# ---------------------
def disp_message(msg: str):
    """ユーザーにメッセージボックスを表示"""
    ui = get_ui()
    if ui:
        ui.messageBox(msg)

# ---------------------
## Component &amp; Sketch Functions
# ---------------------
# /////////////////////////////////////////////////////////////
def get_root_component() -&gt; Optional&#91;adsk.fusion.Component]:
    """ルートコンポーネントを返す"""
    design = get_design()
    return design.rootComponent if design else None

# /////////////////////////////////////////////////////////////
def get_active_component() -&gt; Optional&#91;adsk.fusion.Component]:
    """現在アクティブなコンポーネントを返す"""
    design = get_design()
    return design.activeComponent if design else None

# /////////////////////////////////////////////////////////////
def create_new_component(name: str = 'New_Component') -&gt; Optional&#91;adsk.fusion.Component]:
    """新しいコンポーネントを作成し、アクティブなコンポーネントの配下に追加"""
    component = get_active_component()
    if not component:
        component = get_root_component()
    
    if not component:
        disp_message('コンポーネントが見つかりません。デザインがアクティブか確認してください。')
        return None
    
    try:
        occurrences = component.occurrences
        new_occurrence = occurrences.addNewComponent(adsk.core.Matrix3D.create())
        new_component = new_occurrence.component
        new_component.name = name
        return new_component
    except Exception:
        disp_message(f'新しいコンポーネントの作成に失敗しました:\n{traceback.format_exc()}')
        return None

# /////////////////////////////////////////////////////////////
def get_parent_sketch(obj: any) -&gt; Optional&#91;adsk.fusion.Sketch]:
    """指定されたオブジェクトの親スケッチを取得"""
    return obj.parentSketch if hasattr(obj, 'parentSketch') else None

# /////////////////////////////////////////////////////////////
def create_new_sketch(name: str = 'New_Sketch', plane: str = 'xy') -&gt; Optional&#91;adsk.fusion.Sketch]:
    """指定された平面に新しいスケッチを作成"""
    component = get_active_component()
    if not component:
        component = get_root_component()
    
    if not component:
        disp_message('スケッチを作成するコンポーネントが見つかりません。')
        return None
    
    plane = plane.lower()
    planes_map = {
        "xy": component.xYConstructionPlane,
        "xz": component.xZConstructionPlane,
        "yz": component.yZConstructionPlane
    }
    
    base_plane = planes_map.get(plane)
    if not base_plane:
        disp_message(f"サポートされていない平面: '{plane}' 'xy', 'xz', 'yz' のいずれかを選択してください。")
        return None
        
    try:
        sketches = component.sketches
        sketch = sketches.add(base_plane)
        sketch.name = name
        return sketch
    except Exception:
        disp_message(f'新しいスケッチの作成に失敗しました:\n{traceback.format_exc()}')
        return None

# /////////////////////////////////////////////////////////////
def is_sketch_mode_active() -&gt; Tuple&#91;bool, Optional&#91;adsk.fusion.Sketch]]:
    """現在スケッチモードがアクティブであるかを確認し、スケッチオブジェクトを返す"""
    app = get_app()
    active_object = app.activeEditObject
    # is_instance() を使うことで、より安全に型チェックを行う
    if isinstance(active_object, adsk.fusion.Sketch):
        return True, active_object
    else:
        return False, None

# /////////////////////////////////////////////////////////////
def get_sketch() -&gt; Optional&#91;adsk.fusion.Sketch]:
    """アクティブなスケッチを返す、アクティブでない場合は新しいスケッチを作成"""
    is_active, sketch = is_sketch_mode_active()
    if not is_active:
        sketch = create_new_sketch()
    return sketch
</code></pre>



<h4 class="wp-block-heading"><span id="toc16">lib_2d.py</span></h4>



<pre class="wp-block-code has-cocoon-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-10"><code>import adsk.core, adsk.fusion, adsk.cam, traceback
from typing import Tuple, Optional

# 利用するlib_utilは、このライブラリと同じディレクトリ
import os, sys, importlib
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(current_dir)
import lib_util

# ---------------------
## カスタム、点基本クラス
# ---------------------
# /////////////////////////////////////////////////////////////
class kPoint:
    """3D空間の点を表す基本クラス"""
    def __init__(self, x: float, y: float, z: float = 0.0):
        self.x = x
        self.y = y
        self.z = z

# ---------------------
## カスタム、スケッチ点クラス
# ---------------------
# /////////////////////////////////////////////////////////////
class kSketchPoint(kPoint):
    """Fusion 360 のスケッチ点として使用される座標を、単位とスケッチ平面に応じて変換するクラス"""
    def __init__(self, x: float = 0.0, y: float = 0.0, z: float = 0.0, sketch: Optional&#91;adsk.fusion.Sketch] = None, unit: str = "mm"):
        unit = unit.lower()
        # 単位変換係数を辞書で管理
        scale_factors = {"mm": 0.1, "cm": 1.0, "m": 10.0}
        scale = scale_factors.get(unit, 1.0) # 存在しない単位は1.0 (cm) を使用

        if not sketch:
            sketch = lib_util.get_sketch() # スケッチが指定されていなければ、アクティブなスケッチを取得

        # スケッチ平面に応じて座標系を調整 (XZ平面はY軸が下向き)
        # 参照平面が'XZ'の場合は、y座標を反転させる
        # これはFusion 360の座標系の癖に対応
        direction_y = -1.0 if sketch and sketch.referencePlane.name == "XZ" else 1.0
        
        # 単位と座標系による方向を調整
        converted_x = x * scale
        converted_y = y * scale * direction_y
        converted_z = z * scale
        
        super().__init__(converted_x, converted_y, converted_z)
        self.sketch = sketch
        self.unit = unit
        
# ---------------------
## Sketch Geometry Creation Functions
# ---------------------
# /////////////////////////////////////////////////////////////
def is_equal_sketch_points(sp1: adsk.fusion.SketchPoint, sp2: adsk.fusion.SketchPoint, tolerance: float = 0.0001) -&gt; bool:
    """2つのスケッチ点が指定された許容差内で同じ位置にあるかどうかを判断"""
    # ジオメトリオブジェクトの距離を比較
    distance = sp1.geometry.distanceTo(sp2.geometry)
    return distance &lt; tolerance

# /////////////////////////////////////////////////////////////
def create_sketch_point(x: float = 0, y: float = 0, z: float = 0, sketch: Optional&#91;adsk.fusion.Sketch] = None) -&gt; Optional&#91;adsk.fusion.SketchPoint]:
    """指定された座標にスケッチ点を作成"""
    if not sketch:
        sketch = lib_util.get_sketch()
    
    if not sketch:
        lib_util.disp_message('スケッチがアクティブでないか、新しいスケッチの作成に失敗しました。')
        return None
        
    try:
        # kSketchPoint を使用して単位と平面を考慮した座標を取得
        converted_point = kSketchPoint(x, y, z, sketch)
        # adsk.core.Point3D オブジェクトを作成
        point3d = adsk.core.Point3D.create(converted_point.x, converted_point.y, converted_point.z)
        # スケッチに点を追加
        sketchPoint = sketch.sketchPoints.add(point3d)
        return sketchPoint
    except Exception:
        lib_util.disp_message(f'スケッチ点の作成に失敗しました:\n{traceback.format_exc()}')
        return None

# /////////////////////////////////////////////////////////////
def create_line_from_sketchpoints(sp1: adsk.fusion.SketchPoint, sp2: adsk.fusion.SketchPoint, construction: bool = False, fixed: bool = False) -&gt; Optional&#91;adsk.fusion.SketchLine]:
    """2つの既存のスケッチ点から直線を作成"""
    # 同じスケッチに属しているかチェック
    if lib_util.get_parent_sketch(sp1) != lib_util.get_parent_sketch(sp2):
        lib_util.disp_message('2つの点は異なるスケッチに属しています。')
        return None
        
    # 2つの点が同じ位置にあるかチェック
    if is_equal_sketch_points(sp1, sp2):
        lib_util.disp_message('2つの点が同じ位置にあります。直線を作成できません。')
        return None
        
    sketch = lib_util.get_parent_sketch(sp1)
    if not sketch:
        lib_util.disp_message('親スケッチが見つかりません。')
        return None
        
    try:
        line = sketch.sketchCurves.sketchLines.addByTwoPoints(sp1, sp2)
        line.isConstruction = construction
        line.isFixed = fixed
        return line
    except Exception:
        lib_util.disp_message(f'直線（スケッチ点から）の作成に失敗しました:\n{traceback.format_exc()}')
        return None

# /////////////////////////////////////////////////////////////
def create_line_from_coordinate(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float, sketch: Optional&#91;adsk.fusion.Sketch] = None, construction: bool = False, fixed: bool = False) -&gt; Optional&#91;adsk.fusion.SketchLine]:
    """座標から直接、スケッチ直線を作成"""
    if not sketch:
        sketch = lib_util.get_sketch()

    if not sketch:
        return None

    # ヘルパー関数を利用して点を先に作成
    p1 = create_sketch_point(x1, y1, z1, sketch)
    p2 = create_sketch_point(x2, y2, z2, sketch)
    
    if p1 and p2:
        return create_line_from_sketchpoints(p1, p2, construction, fixed)
    else:
        lib_util.disp_message('直線を作成するための点の作成に失敗しました。')
        return None

# /////////////////////////////////////////////////////////////
def create_line_from_points(p1: kPoint, p2: kPoint, sketch: Optional&#91;adsk.fusion.Sketch] = None, construction: bool = False, fixed: bool = False) -&gt; Optional&#91;adsk.fusion.SketchLine]:
    """カスタム `kPoint` オブジェクトからスケッチ直線を作成"""
    if not sketch:
        sketch = lib_util.get_sketch()
    
    if not sketch:
        return None
        
    return create_line_from_coordinate(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, sketch, construction, fixed)

# /////////////////////////////////////////////////////////////
def draw_center_line(widthX=100,widthY=100,widthZ=100):
    """センターライン作成"""
    widthX = 100 if widthX == 0 else widthX
    widthY = 100 if widthY == 0 else widthY
    widthZ = 100 if widthZ == 0 else widthZ
    wx=widthX/2
    wy=widthY/2
    wz=widthZ/2
    sketch = lib_util.get_sketch()
    xp1 = kPoint(-wx,0)
    xp2 = kPoint(wx,0)
    yp1 = kPoint(0,-wy)
    yp2 = kPoint(0,wy)
    zp1 = kPoint(0,0,-wz)
    zp2 = kPoint(0,0,wz)
    create_line_from_points(xp1,xp2,sketch,True,True) #X Axis
    create_line_from_points(yp1,yp2,sketch,True,True) #Y Axis
    create_line_from_points(zp1,zp2,sketch,True,True) #Z Axis
</code></pre>



<h2 class="wp-block-heading"><span id="toc17">注意点</span></h2>



<p class="wp-block-paragraph">実は、まだ解決できていない注意点があります<br>通常のライブラリ使用では問題ないと思いますが、Fusionでライブラリを利用したスクリプトを実行後、<span class="marker-under-red">ライブラリ内スクリプトを編集しても、編集内容が反映されません。</span><br>Aiに聞いてみると、Fusionの仕様でキャッシュが優先されているとの事です<br>キャッシュクリアのコードも教えてもらいましたが、現状では反映されません。<br><span class="marker-under-red">ライブラリの編集を反映させるには、Fusionを再起動</span>させるとキャッシュがクリアされ反映されます<br>ライブラリを試行錯誤している場合でも、ちょっと面倒です。<br>いい方法は、ないのかなぁ～？？</p>



<h2 class="wp-block-heading"><span id="toc18">まとめ</span></h2>



<p class="wp-block-paragraph">pythonはド素人なので、勉強もかねて、Ai にコーディングを教えてもらいながら、FusionのComponentやsketch、直線作成などの関数をライブラリ化してみました。<br>Fusionオブジェクトモデルは、広範囲で奥が深いので、探すのも大変です。<br>よく使いそうな関数を、まとめたので、少しは取り組みやすくなるのではないか？と思っています。<br>今後も進化させようと思っていますが、Aiがなかったら、ここまで完成できなかったと思います。<br>ここで紹介しているコードも、一旦自分なりに作成したスクリプトを、Aiに張り付けて、添削してもらったコードを再編集したものです。<br>関数名やコメントの書き方なども、pythonの慣習を教えてもらい参考にしています</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
