スキップしてメイン コンテンツに移動

blenderで面と線の交点をだす 線を交点まで伸ばす アドオンとスクリプト

chatgptに聞きながらだ2日ほどでできた



bl_info = {
    "name": "Edge-Plane Intersection (Multi)",
    "author": "ChatGPT + You",
    "version": (1, 1),
    "blender": (2, 80, 0),
    "location": "3Dビュー > 編集モード > メッシュ > Edge-Plane Intersection (Multi)",
    "description": "複数エッジの頂点を面の交点にスナップ",
    "category": "Mesh",
}

import bpy
import bmesh
from mathutils import geometry

def get_global_coords(obj, v):
    return obj.matrix_world @ v.co

def get_local_coords(obj, global_co):
    return obj.matrix_world.inverted() @ global_co

class MESH_OT_edge_plane_intersection_multi(bpy.types.Operator):
    bl_idname = "mesh.edge_plane_intersection_multi"
    bl_label = "Edge-Plane Intersection (Multi)"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        obj = context.active_object
        return (obj is not None and obj.type == 'MESH' and context.mode == 'EDIT_MESH')

    def execute(self, context):
        obj = bpy.context.edit_object
        bm = bmesh.from_edit_mesh(obj.data)
        bm.faces.ensure_lookup_table()
        bm.edges.ensure_lookup_table()
        bm.verts.ensure_lookup_table()

        selected_faces = [f for f in bm.faces if f.select]
        selected_edges = [e for e in bm.select_history if isinstance(e, bmesh.types.BMEdge)]

        if len(selected_faces) != 1:
            self.report({'WARNING'}, "面を1枚明示的に選択してください")
            return {'CANCELLED'}
        if len(selected_edges) < 1:
            self.report({'WARNING'}, "エッジを1本以上明示的に選択してください")
            return {'CANCELLED'}

        face = selected_faces[0]
        plane_verts = face.verts[:3]
        plane_co = get_global_coords(obj, plane_verts[0])
        plane_no = face.normal @ obj.matrix_world.to_3x3().transposed()

        moved_count = 0
        for edge in selected_edges:
            v1, v2 = edge.verts
            p1 = get_global_coords(obj, v1)
            p2 = get_global_coords(obj, v2)
            intersect = geometry.intersect_line_plane(p1, p2, plane_co, plane_no)

            if intersect is None:
                continue

            d1 = (intersect - p1).length
            d2 = (intersect - p2).length
            target_vert = v1 if d1 < d2 else v2
            target_vert.co = get_local_coords(obj, intersect)
            moved_count += 1

        bmesh.update_edit_mesh(obj.data, loop_triangles=False, destructive=False)
        self.report({'INFO'}, f"{moved_count}個の頂点を交点に移動しました")
        return {'FINISHED'}

def menu_func(self, context):
    self.layout.operator(MESH_OT_edge_plane_intersection_multi.bl_idname)

def register():
    bpy.utils.register_class(MESH_OT_edge_plane_intersection_multi)
    bpy.types.VIEW3D_MT_edit_mesh.append(menu_func)

def unregister():
    bpy.types.VIEW3D_MT_edit_mesh.remove(menu_func)
    bpy.utils.unregister_class(MESH_OT_edge_plane_intersection_multi)

if __name__ == "__main__":
    register()


✅ 導入方法
上記コードを edge_to_plane_intersection.py という名前で保存
Blender > 編集 > プリファレンス > アドオン
インストール ボタンでこの .py ファイルを読み込む
チェックを入れて有効化

✅ 使用方法(変わらず)
編集モードで:
面1枚を選択(順序が重要)
そのあと エッジを複数明示的に選択(Shift+右クリック)
メニューから実行:
メッシュ > Edge-Plane Intersection (Multi)



開発段階ではスクリプトのほうが触りやすい
こちらが伸ばせる線は一本だけ
スクリプト



import bpy
import bmesh
from mathutils import Vector, geometry

def get_global_coords(obj, v):
    return obj.matrix_world @ v.co

def get_local_coords(obj, global_co):
    return obj.matrix_world.inverted() @ global_co

def main():
    obj = bpy.context.edit_object
    if obj is None or obj.type != 'MESH':
        print("メッシュオブジェクトを選択してください")
        return

    bm = bmesh.from_edit_mesh(obj.data)
    bm.faces.ensure_lookup_table()
    bm.edges.ensure_lookup_table()
    bm.verts.ensure_lookup_table()

    # 面の選択(select状態)
    selected_faces = [f for f in bm.faces if f.select]
    print("\n[面選択状態]:", selected_faces)

    # 明示的に選択されたエッジのみ(選択履歴から取得)
    selected_edges = [e for e in bm.select_history if isinstance(e, bmesh.types.BMEdge)]
    print("[エッジ選択状態]:", selected_edges)

    if len(selected_faces) != 1:
        print("⚠️ 面を1枚明示的に選択してください")
        return
    if len(selected_edges) != 1:
        print("⚠️ エッジを1本明示的に選択してください")
        return

    face = selected_faces[0]
    edge = selected_edges[0]

    # エッジの2頂点
    v1, v2 = edge.verts
    p1 = get_global_coords(obj, v1)
    p2 = get_global_coords(obj, v2)

    # 面の最初の3頂点を使って平面作成
    verts = face.verts[:3]
    plane_co = get_global_coords(obj, verts[0])
    plane_no = face.normal @ obj.matrix_world.to_3x3().transposed()

    # 線分と平面の交点を求める
    intersect = geometry.intersect_line_plane(p1, p2, plane_co, plane_no)
    if intersect is None:
        print("⚠️ エッジは面と平行で交点がありません")
        return

    # 交点に近い方の頂点を移動
    d1 = (intersect - p1).length
    d2 = (intersect - p2).length
    target_vert = v1 if d1 < d2 else v2
    target_vert.co = get_local_coords(obj, intersect)

    bmesh.update_edit_mesh(obj.data, loop_triangles=False, destructive=False)
    print("✅ 交点に近い頂点を移動しました")

main()




💾 スクリプトの保存方法
Blenderを開く
上部メニューの Scripting タブをクリック
左上の「+ New」をクリックして新しいテキストを作成
上のコードをコピペ
Text > Save As から intersection_script.py などの名前で保存

▶ 実行方法
編集モード(Edit Mode)で、面1枚と辺1本を選択
上記スクリプトを貼った状態で、右上の「▶ Run Script」ボタンをクリック
→ 交点が自動で作成されます!


スクリプトの実行結果(print)のメッセージとかはコンソールから立ち上げないとでてこない(ubuntu)
ようなのでスクリプトを触るときはblenderをコンソールから立ち上げる
多角形ポリゴンを基準面に選ぶとどうなるかは

✅ 結論から言うと:
歪んだ四角形ポリゴンでも、
Blender はそのポリゴンに対して平均法線ベクトルを定義する。
面の法線から導かれる**「代表平面」を使って、Ax + By + Cz + D = 0 の形で近似的な平面方程式**は得られます。

🧠 技術的に何が起きているか:
プランナー(平面)でない四角形の例:
頂点A, B, C, Dが1平面上にないとき、四角形は実際にはねじれた面(非プラナー面)になります。
Blenderではこのような面の法線は、通常こうして決まります:
面が四角形(N-gon)であっても、Blender内部で三角形に分割(triangulate)して平均する。
例えば、対角線で「三角形ABC」と「三角形ACD」に分け、
それぞれの法線を出して平均(normalize)して、
代表法線 n = normalize(n1 + n2) を取得。
それを「面の法線」として返してきます。


らしい

コメント

このブログの人気の投稿

Arduino IDE が "Downloading index: library_index.tar.bz2" で固まる問題

PCとのシリアル通信が原因の一つらしい '/home/usename/.arduino15/packages' を消すといいらしい ので消すと治った IDEの起動中にフリーズしてたのが治った Downloading index: library_index.tar.bz2 とダウンロード中だったが終了したので起動中のフリーズが起こるようになった

Blogger でp5jsがつかえた

”HTMLビュー”でHTMLを編集  divとcanvasを関連付ければ良いみたい (div id="p5canvas とcreateCanvasの.parent("p5canvas");) p5js本体はCDNを参照(https://cdnjs.com/libraries/p5.js) コードはP5サイトのEXAMPLEから(https://p5js.org/examples/3d-geometries.html) <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script> <div id="p5canvas"></div> <script> function setup() { createCanvas(710, 400, WEBGL).parent("p5canvas"); } function draw() { background(250); translate(-240, -100, 0); normalMaterial(); push(); rotateZ(frameCount * 0.01); rotateX(frameCount * 0.01); rotateY(frameCount * 0.01); plane(70); pop(); translate(240, 0, 0); push(); rotateZ(frameCount * 0.01); rotateX(frameCount * 0.01); rotateY(frameCount * 0.01); box(70, 70, 70); pop(); translate(240, 0, 0); push(); rotateZ(frameCount * 0.01); rotateX(frameCount * 0.01); rotateY(frameCount * 0.01); cylinder(70, 70); pop(); ...

クラスカル法

chat-gptにきいたらおしえてくれた                                                                参考動画 <!DOCTYPE html> <html lang="en"> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script> <div id="p5canvas"></div> <script> class Graph {   constructor() {     this.vertices = [];     this.edges = [];   }   addVertex(x, y) {     this.vertices.push({ x, y });   }   addEdge(source, destination, weight) {     if (this.vertices[source] && this.vertices[destination]) ...