news 2026/9/18 7:28:15

TiXL t3 Symbol Browser:模糊搜索、类型过滤与使用频率排序的算子插入机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TiXL t3 Symbol Browser:模糊搜索、类型过滤与使用频率排序的算子插入机制

TiXL t3 Symbol Browser:模糊搜索、类型过滤与使用频率排序的算子插入机制

【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3

本文以 TiXL t3(开源实时动态图形工具,项目路径GitHub_Trending/t3/t3)编辑器的 Symbol Browser(算子浏览器)为主题,讲解如何通过长按/双击画布或 Tab 键唤起该弹窗、在图中选定位置放置算子,并结合 SymbolBrowser.cs、SymbolFilter.cs 与 SymbolAnalysis.cs 的源码,剖析模糊搜索、输入类型过滤、使用频率排序以及“拖线先行”自动连接等机制的底层实现。

一、Symbol Browser 是什么,如何唤起

按官方帮助文档 SymbolBrowser.md 的定义,Symbol browser 是你用来查找算子(operator/symbol)并将其放置到图(graph)上指定位置的弹窗。它的核心交互包括:

  • 长按(或双击)空白画布打开浏览器,然后直接键入文字搜索;
  • 搜索支持同义/缩写匹配——例如输入 "LFO" 即使不是算子的名字,也能找到振荡器(oscillator);
  • 放置前可预览每个算子的产出效果;
  • 若先拖出一条连接线,浏览器只列出能匹配该输入类型的算子
  • 单个被选中的算子上按 Tab,可内联插入新算子;
  • 候选项按“人们实际使用频率”排序,常用算子浮在顶部。

源码层面,该弹窗对应 SymbolBrowser 类,注释说明它“表示 GraphView 上新 GraphNode 的占位符,可与其他节点连接并提供搜索功能,本质上是 T2 的 CreateOperatorWindow”。它在 GraphView.cs#L107 中随视图构造创建:

graphView.SymbolBrowser = new SymbolBrowser(projectView, graphView);

唤起入口是OpenAt方法(SymbolBrowser.cs#L39-L75),签名揭示了它承载的全部过滤语义:

public void OpenAt(Vector2 positionOnCanvas, Type filterInputType, // 只保留有该类型输入的算子 Type filterOutputType, // 只保留有该类型输出的算子 bool onlyMultiInputs, // 仅保留多输入槽算子 string startingSearchString = "", System.Action<Symbol> overrideCreate = null)

其中positionOnCanvas就是文档所说的“at a chosen spot”——新算子最终会以该坐标落入图中(见下文CreateInstance)。OpenAt还做了一个体验优化:若放置点太靠近窗口边缘,会先调用Canvas.FitAreaOnCanvas平移画布,避免浏览器被裁切(L41-L55)。

Tab 内联插入的路径可以在Draw()的未打开分支中找到(SymbolBrowser.cs#L81-L128):

  • 若当前恰好选中一个算子,按 Tab 会走ConnectionMaker.OpenBrowserWithSingleSelection(定义于 ConnectionMaker.cs#L699),在新算子插入后自动建立与选中算子的连接——这就是文档所说的“inline insert”;
  • 若没有选中算子,则启动ConnectionMaker.StartOperation(_graphView, "Add operator")并在鼠标位置打开浏览器(L91-L96)。

二、打字即搜:查询如何被编译成模糊正则

文档称搜索“matches synonyms too”(能匹配同义词/缩写)。从源码看,这一能力来自 SymbolFilter 的查询编译逻辑。UpdateFilters对输入串做了两步处理(SymbolFilter.cs#L69-L102):

1. 两段式语法分离“算子名 + 预设名”。若查询含空格,正则(.+?)\s+(.*)会把查询拆成symbolFilter(前段,用于匹配算子)和PresetFilterString(后段,用于筛选预设):

// Check if template search was initiated var twoPartSearchResult = new Regex(@"(.+?)\s+(.*)").Match(search); if (twoPartSearchResult.Success) { symbolFilter = twoPartSearchResult.Groups[1].Value; presetFilter = twoPartSearchResult.Groups[2].Value; }

2. 逐字符插入.*构建模糊正则。搜索词"LFO"会被编译为L.*F.*O(忽略大小写):

var pattern = string.Join(".*", symbolFilter.ToCharArray()); searchRegex = new Regex(pattern, RegexOptions.IgnoreCase);

这正是 “LFO 能找到振荡器”的机制:只要算子名中 L、F、O 三个字符按序出现(如 Low/Frequency/Oscillator 类命名)即可命中,无需字面包含 "LFO"。匹配时(L156-L160)满足以下任一条件即入选:

  • 正则匹配算子名字_currentRegex.IsMatch(symbolUiSymbol.Name));
  • 命名空间包含过滤词(忽略大小写的子串包含);
  • 描述文本包含过滤词。

命中集合随后按相关度排序并截断到前 100 条(L174-L180),保证浏览器响应始终流畅。另外,UpdateMatchingSymbols会先把“当前组合及其所有祖先算子”的 Id 收集进parentSymbolIds并跳过(L106-L120)——这是为了防止把算子放进会形成循环引用的自己/祖先内部。

浏览器主列表的绘制在DrawResultsList(SymbolBrowser.cs#L264-L380):每项以算子第一个输出的数据类型取色作为背景,属于Lib.Types.Examples.Lib.、当前用户项目或当前组合命名空间的算子颜色饱和,其余命名空间的颜色淡出到 40%(color.Fade(0.4f)),让用户一眼区分核心库与边缘算子。支持方向键上下移动高亮、滚轮/滚动自动跟随,鼠标悬停也会即时切换选中项。

三、“拖线先行”:按连接类型过滤候选算子

文档中“如果先拖出连接线,浏览器只列出适配该输入的算子”对应OpenAtfilterInputType/filterOutputType/onlyMultiInputs参数,在 SymbolFilter.UpdateMatchingSymbols 中强制执行:

if (_inputType != null) { if (symbolUiSymbol.InputDefinitions.Count == 0) continue; // 优先第一个输入类型匹配;否则任意输入匹配 if (symbolUiSymbol.InputDefinitions[0].ValueType != _inputType) { var matchingInput = symbolUiSymbol.InputDefinitions.FirstOrDefault(i => i.ValueType == _inputType); if (matchingInput == null) continue; } var matchingInputDef = symbolUiSymbol.GetInputMatchingType(FilterInputType); if (matchingInputDef == null) continue; // 新连接落在第一个匹配类型的输入上,所以它必须是多输入槽... if (OnlyMultiInputs && !matchingInputDef.IsMultiInput) continue; }

这段代码解释了OnlyMultiInputs存在的原因:新连接会落在第一个匹配类型的输入槽上,因此当用户从已有输入槽继续拖线(该槽可能已占位)时,只保留支持多输入(multi-input)的算子,确保新连接能挂接成功。

过滤生效后,浏览器列表顶部会打印类型过滤头(PrintTypeFilter,SymbolBrowser.cs#L382-L402),格式为输入类型[多输入标记] -> 输出类型,例如float[..] -> float,让操作者明确当前候选集合的约束。

四、排序算法:为什么“常用的算子浮在顶部”

文档称“suggestions are ranked by how often people actually use them”。实现位于SymbolFilter.ComputeRelevancy(SymbolFilter.cs#L199-L409),它为一个算子累积一系列乘性相关度因子。可确认的因子如下:

条件因子源码位置
单字符查询且算子名以其开头×20L216-L219
名字与查询完全相等(忽略大小写)×8.6L227-L231
名字前缀匹配×8.5L233-L237
名字包含查询×8.4L240-L245
描述文本包含查询×1.01L247-L252
Pascal 缩写匹配(查询字符按序命中名字大写字母,如 "ds" → "DrawState")×4L255-L279
命名空间以Types.开头×4L221-L225
命名空间以Lib开头×3L287-L288
命名空间以examples开头×2L290-L294
与当前项目同包(同 SymbolPackage)×2L310-L315
命名空间以当前项目/组合的根命名空间开头×1.9L318-L335
属于用户可编辑项目(EditableSymbolProject×1.9L339-L343
命名空间含dx11或下划线×0.1L281-L285
名字以_开头(内部算子)×0.1L297-L301
名字含OBSOLETE×0.01L303-L304
标签为 Obsolete/NeedsFix/Research/Internal×0.3L385-L389
标签为 Advanced×0.8L391-L395
标签为 Essential×1.5L397-L401

两个“使用频率”因子最能体现文档所述的排序意图:

1. 高频连接组合加成(L345-L365)。SymbolAnalysis会统计所有项目中“输出槽 → 输入槽”连接对的哈希计数(SymbolAnalysis.cs#L24-L27 注释明确写着 “Used by SymbolBrowser for relevancy weighting of frequent combinations”)。若候选算子的输出槽恰好常与当前拖线来源的输入槽配对,相关度乘以1 + 4·count^(1/3)——即“社区里常用的一条接线”会显著上浮。

2. 全局使用量加成(L367-L383)。当算子经过上述检查后相关度已超过 10(即确实相关),再乘以其被实例化次数的加成:

var count = SymbolAnalysis.InformationForSymbolIds.TryGetValue(symbol.Id, out var info) ? info.UsageCount : 0; var totalUsageCountBoost = (float)(1 + (500.0 * (float)count / SymbolAnalysis.TotalUsageCount)); relevancy *= totalUsageCountBoost;

UsageCount由 SymbolAnalysis.UpdateSymbolUsageCounts 遍历所有包的算子子项统计而来,因此被大量组合引用的算子会自然排在前面——与文档“ranked by how often people actually use them”的表述一一对应。

五、放置与创建流程:从点击到可撤销的“Insert Op”

选中某项后(回车确认,或单击/双击列表项),CreateInstance执行完整落盘流程(SymbolBrowser.cs#L551-L640):

  1. 按位置插入子节点AddSymbolChildCommand(parentSymbol, symbol.Id) { PosOnCanvas = PosOnCanvas }将新算子以浏览器打开时的画布坐标加入当前组合(L565-L567)——这就是“placed at a chosen spot”的实现;
  2. 应用预设(如有):若两段式搜索选中了某个 preset,则presetPool.Apply(newInstance, _selectedPreset)把该 Variation 预设写入新实例(L580-L584);
  3. 自动连接拖线前留下的临时连接:遍历ConnectionMaker.GetTempConnectionsFor得到的草稿连接,按类型在新算子上找匹配槽位(GetOutputMatchingType/GetInputMatchingType),为每条连接生成AddConnectionCommand(L593-L633);
  4. 合并为一次可撤销操作ConnectionMaker.CompleteOperation(_graphView, commandsForUndo, "Insert Op " + ...)把“插入算子 + 全部连接”打包进撤销栈,一次 Ctrl+Z 全部回退(L637);
  5. 自动弹出参数窗口ParameterPopUp.NodeIdRequestedForParameterWindowActivation = newSymbolChild.Id,放完即可调参(L638)。

面板自身的布局也有细节:搜索框下方 40 像素处渲染结果列表(BrowserPositionOffset),列表基准尺寸为250×300 × (2,1) × UiScaleFactor(L648-L656);ClampPanelToCanvas会把超出窗口右缘/下缘的面板回移或压缩(L404-L419);按住搜索框拖动还能整体平移浏览器位置(DrawSearchInput中的IsMouseDragging分支,L239-L242)。取消操作同样宽松:Esc、右键或点击窗口外都会Cancel(),内部调用ConnectionMaker.AbortOperation丢弃草稿连接(L223-L255)。

六、预设面板与描述/示例预览

文档提到放置前可预览算子的产出。除列表项本身的类型色预览外,源码还确认了右侧辅助面板(从源码结构看,这是浏览器提供“预览/上下文”的主要载体):

  • 描述与示例面板DrawDescriptionPanel(SymbolBrowser.cs#L473-L513):当高亮算子有Description或通过ExampleSymbolLinking.ExampleIdsForSymbolsId关联到示例算子时,在结果列表旁渲染说明文字与 "Example" 条目,帮助用户在放置前了解该算子能做什么;
  • 预设面板DrawPresetPanel(SymbolBrowser.cs#L423-L471):当使用两段式搜索(如noise grain)且算子存在 Variation 预设时,列出标题包含预设过滤词的条目;点击即创建实例并应用该预设(CreateInstancepresetPool.Apply生效)。

面板定位由TryFindValidPanelPosition保证不越出窗口右缘,放不下时翻转到左侧(L515-L534)。

七、关键文件索引

关注点文件
浏览器 UI、Tab 唤起、放置与创建流程SymbolBrowser.cs
查询编译、类型过滤、相关度排序SymbolFilter.cs
使用量/连接频率统计(排序数据源)SymbolAnalysis.cs
浏览器实例化入口GraphView.cs
Tab 单选内联插入与临时连接管理ConnectionMaker.cs
官方行为描述(本文主体依据)SymbolBrowser.md

掌握以上内容后,你可以完整解释 t3 图中“长按画布 → 输入 LFO 命中振荡器 → 列表按使用频率排序 → 回车落点并自动连线”这一整条高频工作流:查询如何被编译为字符级模糊正则、拖线为何只剩“接得上”的算子、以及SymbolAnalysis的用量与连接统计如何把常用算子推到列表顶端。

【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 7:26:24

CANN社区邮件列表使用指南:订阅、退订、公共存档与邮件投递实操

CANN社区邮件列表使用指南&#xff1a;订阅、退订、公共存档与邮件投递实操 【免费下载链接】infrastructure 本仓库用于托管CANN社区基础设施团队的公开信息&#xff0c;包括不限于&#xff1a;会议日程&#xff0c;成员信息&#xff0c;服务文档和配置等信息 项目地址: htt…

作者头像 李华
网站建设 2026/9/18 7:26:24

AI内容无损转Word:Markdown、Mermaid与LaTeX的完美转换指南

最近做一套技术归档材料&#xff0c;我把几个大模型生成的方案、流程图和公式整理进了Word。一开始图省事&#xff0c;直接在对话窗口里全选复制&#xff0c;粘贴到Word的瞬间我就知道完了——标题层级全丢&#xff0c;列表变成一堆星号和井号&#xff0c;Mermaid代码原封不动躺…

作者头像 李华
网站建设 2026/9/18 7:25:54

3ds Max 2026零基础生存指南:从界面恐惧到空间直觉

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 7:25:21

Oh My Zsh cpanm 插件完全指南:为 cpanminus 补齐命令行补全

Oh My Zsh cpanm 插件完全指南&#xff1a;为 cpanminus 补齐命令行补全 【免费下载链接】ohmyzsh &#x1f643; A delightful community-driven (with 2,500 contributors) framework for managing your zsh configuration. Includes 300 optional plugins (rails, git, macO…

作者头像 李华
网站建设 2026/9/18 7:22:47

19英寸机柜设计:从安装孔距到钣金折弯的工程指南

简介&#xff1a;19英寸机柜与机箱设计规范标准PDF&#xff0c;是一份面向电子设备结构设计、机箱机柜制造及IT运维人员的标准参考资料。文档以19英寸规格为脉络&#xff0c;系统讲解1U与1TE单位定义、19英寸宽度标准&#xff08;426.72mm/84TE&#xff09;、Cabinet与Rack两类…

作者头像 李华
网站建设 2026/9/18 7:20:34

Transformer-LSTM混合模型:锂电池剩余寿命预测实战

简介&#xff1a;面向新能源与电池管理领域的数据科学从业者及研究生&#xff0c;这份Python项目实例基于Transformer-LSTM混合模型实现锂电池剩余寿命&#xff08;RUL&#xff09;预测&#xff0c;覆盖数据预处理、滑动窗口采样、特征工程、模型训练优化全流程&#xff0c;并集…

作者头像 李华