🐴 قىستۇرما ياساش ياردەمچىسى  ·  节点制作助手  ·  Plugin Maker Helper

ئۇمۇمىي چۈشەنچە概述Overview

بۇ بەت سىزگە ئۆزىڭىزنىڭ قىستۇرما نودى (plugin node) يېزىپ، «يۈگەنلىك ئات» قىستۇرمىسىغا قوشۇشقا ياردەم بېرىدۇ. بىر دانە .rb ھۆججىتى يېزىپ، تەڭشەكتىكى «نود قاچىلاش» بېتىدىن قاچىلسىڭىز بولىدۇ. تۆۋەندە ھەر بىر بۆلۈمنىڭ كود قېلىپى ۋە تەپسىلىي چۈشەندۈرۈشى بېرىلدى. 本助手帮助你编写自己的插件节点,并通过设置中的“安装节点”页面装入草图大师参数化设计。下面给出每个部分的代码模板与详细说明。 This helper lets you author your own plugin node and install it into the Sketchupat3.0 extension via the Settings → Node Install page. Each section below provides a copy-ready code template plus explanation.

بۇ بەت قىستۇرما ئىچىدىكى «قىستۇرما ياساش چۈشەندۈرۈشى» تۇگمىسىنى بېسىپمۇ ئېچىلىدۇ. 在插件内点击“如何制作节点”按钮也可打开本页。 You can also open this page from inside the extension via the “How to build a node” button.

قۇرۇلما结构Architecture

ھەر بىر قىستۇرما نودى ئىككى قىسىمدىن تۈزۈلىدۇ: 每个插件节点由两部分组成: Every plugin node has two parts:

ئەڭ كىچىك قېلىپ最小模板Minimal template

تۆۋەندىكى قېلىپنى كۆچۈرۈپ، key ۋە ئىسىملىرىنى ئۆزىڭىزچە ئالماشتۇرۇپ ئىشلىتىڭ: 复制下面的模板,把 key 和名称替换成你自己的: Copy the template below and replace key and the names with your own:

module Sketchupat
  NodeRegistry.register(
    key:      'my_node',          # نودنىڭ بىردىنبىر كودى (type بىلەن ئوخشاش)
    category: 'plugins',          # كۆرسىتىلىدىغان تۈر (plugins = قىستۇرما)
    icon:     '⭐',               # كۆرسەتمە بەلگە (emoji)
    source:   'plugin',
    name:     'مېنىڭ نودۇم',
    author:   'your name',
    color:    '#f59e0b',
    desc:     'قىسقىچە چۈشەندۈرۈش',
    inputs:  [],
    outputs: [{ key: 'out', label: '', type: 'geometry' }],
    params:  [{ key: 'size', label: 'چوڭلۇقى', type: 'number', def: 100 }]
  )

  PluginLoader.register_compute('my_node', lambda do |node, nodes_by_id, outputs, model, bake_group, visiting, used_sources|
    ents = bake_group.respond_to?(:entities) ? bake_group.entities : model.active_entities
    s = ((node['params'] || {})['size'] || 100).to_f
    # گېئومېترىيە قۇرۇپ ents غا قوشۇڭ، نەتىجىنى قايتۇرۇڭ
    ents.add_face([
      Geom::Point3d.new(0, 0, 0),
      Geom::Point3d.new(s, 0, 0),
      Geom::Point3d.new(s, s, 0),
      Geom::Point3d.new(0, s, 0)
    ])
  end)
end
module Sketchupat
  NodeRegistry.register(
    key:      'my_node',          # 节点的唯一代码(与 type 相同)
    category: 'plugins',          # 所属分类(plugins = 插件)
    icon:     '⭐',               # 显示图标(emoji)
    source:   'plugin',
    name:     '我的节点',
    author:   'your name',
    color:    '#f59e0b',
    desc:     '简短说明',
    inputs:  [],
    outputs: [{ key: 'out', label: '', type: 'geometry' }],
    params:  [{ key: 'size', label: '大小', type: 'number', def: 100 }]
  )

  PluginLoader.register_compute('my_node', lambda do |node, nodes_by_id, outputs, model, bake_group, visiting, used_sources|
    ents = bake_group.respond_to?(:entities) ? bake_group.entities : model.active_entities
    s = ((node['params'] || {})['size'] || 100).to_f
    # 生成几何并加入 ents,返回结果
    ents.add_face([
      Geom::Point3d.new(0, 0, 0),
      Geom::Point3d.new(s, 0, 0),
      Geom::Point3d.new(s, s, 0),
      Geom::Point3d.new(0, s, 0)
    ])
  end)
end
module Sketchupat
  NodeRegistry.register(
    key:      'my_node',          # unique node code (same as type)
    category: 'plugins',          # category shown (plugins = plugin)
    icon:     '⭐',               # display icon (emoji)
    source:   'plugin',
    name:     'My Node',
    author:   'your name',
    color:    '#f59e0b',
    desc:     'short description',
    inputs:  [],
    outputs: [{ key: 'out', label: '', type: 'geometry' }],
    params:  [{ key: 'size', label: 'Size', type: 'number', def: 100 }]
  )

  PluginLoader.register_compute('my_node', lambda do |node, nodes_by_id, outputs, model, bake_group, visiting, used_sources|
    ents = bake_group.respond_to?(:entities) ? bake_group.entities : model.active_entities
    s = ((node['params'] || {})['size'] || 100).to_f
    # build geometry, add to ents, return it
    ents.add_face([
      Geom::Point3d.new(0, 0, 0),
      Geom::Point3d.new(s, 0, 0),
      Geom::Point3d.new(s, s, 0),
      Geom::Point3d.new(0, s, 0)
    ])
  end)
end

ئېغىز تىپلىرى端口类型Port types

تىپ类型Type مەنىسى含义Meaning مىسال示例Example
numberسان قىممىتى数值numeric valuedef: 10
geometryگېئومېترىيە (جىسىم/سىزىق/يۈز)几何(体/线/面)geometry (body/line/face)type:'geometry'
pointبىر دانە نۇقتا单个点single pointtype:'point'
groupگۇرۇپپا/ComponentInstance组/组件group / componenttype:'group'
textتېكىست كودى文本代码text codetype:'text'
colorرەڭگى颜色colortype:'color'
multi: trueبىر ئېغىزغا كۆپ سىم ئۇلاش一个端口允许多根连线allow multiple wires on one port{ key:'pts', type:'geometry', multi:true }
كۆپ نۇقتا ئۈچۈن multi: true بەرىڭ؛ گېئومېترىيە كىرگۈزۈشىگە بىر دانە «نۇقتا/سىزىق» گېئومېترىيەسىنى ئۇلىسىڭىز، ھەر بىر نۇقتىسىغا بىردىن نەرسە قۇيۇلىدۇ. 多连接请设 multi: true;把一条“点/线”几何连到 geometry 输入,即可在每个顶点上生成一个副本。 For multi-link set multi: true; wire one “point/line” geometry into a geometry input and a copy is placed at every vertex.

مىسال: كوردىنات نودى示例:坐标节点Example: Coordinate node

بۇ نود x,y,z پارامېتىرى بويىچە بىر كىچىك بەلگە (گېئومېترىيە) قۇرۇپ چىقىرىدۇ — شۇڭا ئېكراندا كۆرۈنىدۇ. 该节点按 x,y,z 参数生成一个标记(几何),因此能在画面中显示。 This node builds a small marker (geometry) at x,y,z, so it is visible on screen.

module Sketchupat
  NodeRegistry.register(
    key:      'coord',
    category: 'plugins',
    icon:     '📍',
    source:   'plugin',
    name:     'كوردىنات',
    author:   'your name',
    color:    '#22c55e',
    desc:     'x,y,z دىن بەلگە قۇرۇيدۇ',
    inputs:  [],
    outputs: [{ key: 'out', label: '', type: 'geometry' }],
    params:  [
      { key: 'x', label: 'X', type: 'number', def: 0 },
      { key: 'y', label: 'Y', type: 'number', def: 0 },
      { key: 'z', label: 'Z', type: 'number', def: 0 }
    ]
  )

  PluginLoader.register_compute('coord', lambda do |node, _n, _o, model, bake_group, _v, _u|
    p  = node['params'] || {}
    x  = (p['x'] || 0).to_f
    y  = (p['y'] || 0).to_f
    z  = (p['z'] || 0).to_f
    s  = 20.0
    ents = bake_group.respond_to?(:entities) ? bake_group.entities : model.active_entities
    # x,y,z دا كىچىك تەكشى يۈز (بەلگە) قۇرۇپ قايتۇرۇش
    grp = ents.add_group
    grp.entities.add_face([
      Geom::Point3d.new(x - s, y - s, z),
      Geom::Point3d.new(x + s, y - s, z),
      Geom::Point3d.new(x + s, y + s, z),
      Geom::Point3d.new(x - s, y + s, z)
    ])
    grp
  end)
end
module Sketchupat
  NodeRegistry.register(
    key:      'coord',
    category: 'plugins',
    icon:     '📍',
    source:   'plugin',
    name:     '坐标',
    author:   'your name',
    color:    '#22c55e',
    desc:     '按 x,y,z 生成标记',
    inputs:  [],
    outputs: [{ key: 'out', label: '', type: 'geometry' }],
    params:  [
      { key: 'x', label: 'X', type: 'number', def: 0 },
      { key: 'y', label: 'Y', type: 'number', def: 0 },
      { key: 'z', label: 'Z', type: 'number', def: 0 }
    ]
  )

  PluginLoader.register_compute('coord', lambda do |node, _n, _o, model, bake_group, _v, _u|
    p  = node['params'] || {}
    x  = (p['x'] || 0).to_f
    y  = (p['y'] || 0).to_f
    z  = (p['z'] || 0).to_f
    s  = 20.0
    ents = bake_group.respond_to?(:entities) ? bake_group.entities : model.active_entities
    # 在 x,y,z 处生成一个平面小标记并返回
    grp = ents.add_group
    grp.entities.add_face([
      Geom::Point3d.new(x - s, y - s, z),
      Geom::Point3d.new(x + s, y - s, z),
      Geom::Point3d.new(x + s, y + s, z),
      Geom::Point3d.new(x - s, y + s, z)
    ])
    grp
  end)
end
module Sketchupat
  NodeRegistry.register(
    key:      'coord',
    category: 'plugins',
    icon:     '📍',
    source:   'plugin',
    name:     'Coordinate',
    author:   'your name',
    color:    '#22c55e',
    desc:     'build a marker at x,y,z',
    inputs:  [],
    outputs: [{ key: 'out', label: '', type: 'geometry' }],
    params:  [
      { key: 'x', label: 'X', type: 'number', def: 0 },
      { key: 'y', label: 'Y', type: 'number', def: 0 },
      { key: 'z', label: 'Z', type: 'number', def: 0 }
    ]
  )

  PluginLoader.register_compute('coord', lambda do |node, _n, _o, model, bake_group, _v, _u|
    p  = node['params'] || {}
    x  = (p['x'] || 0).to_f
    y  = (p['y'] || 0).to_f
    z  = (p['z'] || 0).to_f
    s  = 20.0
    ents = bake_group.respond_to?(:entities) ? bake_group.entities : model.active_entities
    # build a small flat marker at x,y,z and return it
    grp = ents.add_group
    grp.entities.add_face([
      Geom::Point3d.new(x - s, y - s, z),
      Geom::Point3d.new(x + s, y - s, z),
      Geom::Point3d.new(x + s, y + s, z),
      Geom::Point3d.new(x - s, y + s, z)
    ])
    grp
  end)
end

مىسال: كۆپ نۇقتا چېچىش (scatter)示例:多点散布Example: Multi-point scatter

بۇ نود بىر geometry كىرگۈزۈشىگە ئۇلانغان گېئومېترىيەنىڭ ھەر بىر نۇقتىسىغا بىردىن قۇتىدىن قۇيىدۇ. مەسىلەن بىر «سىزىق» ياكى «نۇقتا» گېئومېترىيەسىنى ئۇلىسىڭىز، ھەر بىر نۇقتىغا بىر قۇتىدىن پەيدا بولىدۇ. 该节点把连接到一个 geometry 输入的几何体的每一个顶点都放一个方块。例如连一条“线”或“点”几何,每个顶点处都会出现一个方块。 This node places one box at every vertex of the geometry wired into its geometry input. Wire a “line” or “points” geometry and a box appears at each vertex.

module Sketchupat
  NodeRegistry.register(
    key:      'scatter_box',
    category: 'plugins',
    icon:     '🔳',
    source:   'plugin',
    name:     'چېچىپ قۇتىلاش',
    author:   'your name',
    color:    '#0ea5e9',
    desc:     'گېئومېترىيەنىڭ ھەر بىر نۇقتىسىغا بىردىن قۇتىدىن قۇيىدۇ',
    inputs:  [{ key: 'geom', label: 'گېئومېترىيە', type: 'geometry' }],
    outputs: [{ key: 'out', label: '', type: 'geometry' }],
    params:  [{ key: 'size', label: 'چوڭلۇقى', type: 'number', def: 50 }]
  )

  PluginLoader.register_compute('scatter_box', lambda do |node, nodes_by_id, outputs, model, bake_group, visiting, used_sources|
    eng   = Sketchupat::SketchupatEngine
    geom  = eng.resolve(node, 'geom', nodes_by_id, outputs, model, bake_group, visiting, used_sources)
    return nil unless eng.geometry?(geom)

    # گېئومېترىيەنىڭ بارلىق نۇقتىسىنى يىغىش
    pts = []
    eng.flatten_geom(geom).each do |e|
      if e.is_a?(Sketchup::Edge)
        pts << e.start if e.start
        pts << e.end   if e.end
      elsif e.respond_to?(:vertices)
        e.vertices.each { |vv| pts << vv.position }
      end
    end
    pts.uniq!
    return nil if pts.empty?

    s = ((node['params'] || {})['size'] || 50).to_f
    h = s / 2.0
    ents = bake_group.respond_to?(:entities) ? bake_group.entities : model.active_entities
    grp  = ents.add_group
    pts.each do |pt|
      box = grp.entities.add_group
      box.entities.add_face([
        Geom::Point3d.new(pt.x - h, pt.y - h, pt.z - h),
        Geom::Point3d.new(pt.x + h, pt.y - h, pt.z - h),
        Geom::Point3d.new(pt.x + h, pt.y + h, pt.z - h),
        Geom::Point3d.new(pt.x - h, pt.y + h, pt.z - h)
      ])
    end
    grp
  end)
end
module Sketchupat
  NodeRegistry.register(
    key:      'scatter_box',
    category: 'plugins',
    icon:     '🔳',
    source:   'plugin',
    name:     '散布方块',
    author:   'your name',
    color:    '#0ea5e9',
    desc:     '在几何体的每个顶点处放一个方块',
    inputs:  [{ key: 'geom', label: '几何体', type: 'geometry' }],
    outputs: [{ key: 'out', label: '', type: 'geometry' }],
    params:  [{ key: 'size', label: '大小', type: 'number', def: 50 }]
  )

  PluginLoader.register_compute('scatter_box', lambda do |node, nodes_by_id, outputs, model, bake_group, visiting, used_sources|
    eng   = Sketchupat::SketchupatEngine
    geom  = eng.resolve(node, 'geom', nodes_by_id, outputs, model, bake_group, visiting, used_sources)
    return nil unless eng.geometry?(geom)

    # 收集几何体的所有顶点
    pts = []
    eng.flatten_geom(geom).each do |e|
      if e.is_a?(Sketchup::Edge)
        pts << e.start if e.start
        pts << e.end   if e.end
      elsif e.respond_to?(:vertices)
        e.vertices.each { |vv| pts << vv.position }
      end
    end
    pts.uniq!
    return nil if pts.empty?

    s = ((node['params'] || {})['size'] || 50).to_f
    h = s / 2.0
    ents = bake_group.respond_to?(:entities) ? bake_group.entities : model.active_entities
    grp  = ents.add_group
    pts.each do |pt|
      box = grp.entities.add_group
      box.entities.add_face([
        Geom::Point3d.new(pt.x - h, pt.y - h, pt.z - h),
        Geom::Point3d.new(pt.x + h, pt.y - h, pt.z - h),
        Geom::Point3d.new(pt.x + h, pt.y + h, pt.z - h),
        Geom::Point3d.new(pt.x - h, pt.y + h, pt.z - h)
      ])
    end
    grp
  end)
end
module Sketchupat
  NodeRegistry.register(
    key:      'scatter_box',
    category: 'plugins',
    icon:     '🔳',
    source:   'plugin',
    name:     'Scatter Box',
    author:   'your name',
    color:    '#0ea5e9',
    desc:     'place a box at every vertex of the geometry',
    inputs:  [{ key: 'geom', label: 'Geometry', type: 'geometry' }],
    outputs: [{ key: 'out', label: '', type: 'geometry' }],
    params:  [{ key: 'size', label: 'Size', type: 'number', def: 50 }]
  )

  PluginLoader.register_compute('scatter_box', lambda do |node, nodes_by_id, outputs, model, bake_group, visiting, used_sources|
    eng   = Sketchupat::SketchupatEngine
    geom  = eng.resolve(node, 'geom', nodes_by_id, outputs, model, bake_group, visiting, used_sources)
    return nil unless eng.geometry?(geom)

    # gather all vertices of the geometry
    pts = []
    eng.flatten_geom(geom).each do |e|
      if e.is_a?(Sketchup::Edge)
        pts << e.start if e.start
        pts << e.end   if e.end
      elsif e.respond_to?(:vertices)
        e.vertices.each { |vv| pts << vv.position }
      end
    end
    pts.uniq!
    return nil if pts.empty?

    s = ((node['params'] || {})['size'] || 50).to_f
    h = s / 2.0
    ents = bake_group.respond_to?(:entities) ? bake_group.entities : model.active_entities
    grp  = ents.add_group
    pts.each do |pt|
      box = grp.entities.add_group
      box.entities.add_face([
        Geom::Point3d.new(pt.x - h, pt.y - h, pt.z - h),
        Geom::Point3d.new(pt.x + h, pt.y - h, pt.z - h),
        Geom::Point3d.new(pt.x + h, pt.y + h, pt.z - h),
        Geom::Point3d.new(pt.x - h, pt.y + h, pt.z - h)
      ])
    end
    grp
  end)
end
كۆپ نۇقتا ئۇلىماقچى بولسىڭىز: بىر دانە «نۇقتا» ياكى «سىزىق» نودىنىڭ چىقىشىنى مانا مۇشۇ geom ئېغىزىغا ئۇلاڭ — ھەر بىر نۇقتا بىر قۇتىغا ئايلىنىدۇ. 要散布到多个点:把“点”或“线”节点的输出连到这个 geom 端口,每个点都会生成一个方块。 To scatter across several points: wire a “point” or “line” node's output into this geom port; each point becomes one box.

لوگو تەييارلاش图标准备Logo / icon

نود لوگوسى 200×200 px چوڭلۇقتىكى PNG بولىدۇ. ئىككى ئۇسۇل بار: 节点图标为 200×200 px 的 PNG。有两种方式: Node icon is a 200×200 px PNG. Two ways:

ساقلاش ئورنى: icons/nodes/<key>.png. لوگو قىستۇرما قاچلانغاندا ئاپتوماتىك شۇ يەرگە يېزىلىدۇ. 存放路径: icons/nodes/<key>.png。安装插件时图标会自动写入此处。 Stored at: icons/nodes/<key>.png. The icon is written there automatically on install.

قاچلاش بوغچىسى打包安装Build & install

بىرلا .rb بولسا بىۋاسىتە قاچىلاڭ. بىر نەچچە نود + لوگو بولسا .rbz (zip) قىلىپ ئىسىم بېرىڭ: 单个 .rb 可直接安装。多个节点+图标请打成 .rbz(zip): A single .rb can be installed directly. For several nodes + icons, package as .rbz (zip):

# your_plugin.rbz تەركىبى:
#   star.rb
#   star.png
#   extra_node.rb
#
# قاچىلاش:
#   1) قىستۇرما ئىچىدە «نود قاچىلاش» بېتىنى ئېچىڭ
#   2) «قاچىلا» نى بېسىپ your_plugin.rbz نى تالاڭ
#   3) نود پالىترىدىكى «قىستۇرما» تۈرىگە قوشۇلىدۇ
# your_plugin.rbz 内容:
#   star.rb
#   star.png
#   extra_node.rb
#
# 安装:
#   1) 在插件内打开“安装节点”页面
#   2) 点击“安装”选择 your_plugin.rbz
#   3) 节点会加入面板中的“插件”分类
# contents of your_plugin.rbz:
#   star.rb
#   star.png
#   extra_node.rb
#
# install:
#   1) open the "Node Install" page inside the extension
#   2) click "Install" and pick your_plugin.rbz
#   3) the node is added to the "Plugin" category in the palette

دىققەت نۇقتىلىرى注意事项Important notes