【Unity编辑器拓展】GraphView自定义可视化节点

news2024/9/9 0:24:08

1、创建节点区域脚本

其中的new class UxmlFactory,可以让该元素显示在UI Builder中,我们就可以在Library-Project中看到我们新建的这两个UI元素,就可以拖入我们的UI窗口编辑了

public class NodeTreeViewer : GraphView
{
    public new class UxmlFactory : UxmlFactory<NodeTreeViewer, UxmlTraits> { }
}

默认的GraphView是一片黑屏。在这里,我们给我们的GraphView窗口添加上网格和拖拽缩放功能。

public class NodeTreeViewer : GraphView
{
    public new class UxmlFactory : UxmlFactory<NodeTreeViewer, UxmlTraits> { }

    public NodeTree tree;
    public Action<NodeView> OnNodeSelected;

    public NodeTreeViewer()
    {
        Insert(0, new GridBackground());
        this.AddManipulator(new ContentZoomer());
        this.AddManipulator(new ContentDragger());
        this.AddManipulator(new SelectionDragger());
        this.AddManipulator(new RectangleSelector());
        var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/NodeEditor/Editor/UI/NodeTreeViewer.uss");
        styleSheets.Add(styleSheet);
    }
}

     uss代码参考,上面代码的uss路径要根据项目实际路径进行设置。 

GridBackground{
    --grid-background-color: rgb(40,40,40);
    --line-color: rgba(193,196,192,0.1);
    --thick-line-color: rgba(193,196,192,0.1);
    --spacing: 15;
}

2、创建节点和删除选中元素

2.1 创建节点类

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;

public class NodeView : UnityEditor.Experimental.GraphView.Node
{
    public Node node;
    public Port input;
    public Port output;
    public Action<NodeView> OnNodeSelected;
    public NodeView(Node node)
    {
        this.node = node;
        this.title = node.name;
        this.viewDataKey = node.guid;
        style.left = node.position.x;
        style.top = node.position.y;
        CreateInputPorts();
        CreateOutputPorts();
    }

    //创建输入端口
    private void CreateInputPorts()
    {
        input = InstantiatePort(Orientation.Vertical, Direction.Input, Port.Capacity.Multi, typeof(bool));
        if(input != null )
        {
            input.portName = "";
            inputContainer.Add(input);
        }
    }

    //创建输出端口
    private void CreateOutputPorts()
    {
        output = InstantiatePort(Orientation.Vertical, Direction.Output, Port.Capacity.Multi, typeof(bool));
        if (output != null)
        {
            output.portName = "";
            outputContainer.Add(output);
        }
    }

    //选中该节点时传递事件
    public override void OnSelected()
    {
        base.OnSelected();
        if( OnNodeSelected != null )
        {
            OnNodeSelected?.Invoke(this);
        }
    }

    //设置生成时位置
    public override void SetPosition(Rect newPos)
    {
        base.SetPosition(newPos);
        node.position.x = newPos.xMin;
        node.position.y = newPos.yMin;
    }

}

2.2 节点区域创建节点和删除选中元素功能 


    //重写该方法,可以添加右键菜单按钮
    public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
    {
        var types = TypeCache.GetTypesDerivedFrom<Node>();
        foreach (var type in types)
        {
            evt.menu.AppendAction($"创建节点/{type.Name}", a => CreateNode(type));
        }
        evt.menu.AppendAction("删除选中元素", DeleteSelecteNode);
    }

    //删除选中元素,节点或者连线
    private void DeleteSelecteNode(DropdownMenuAction action)
    {
        DeleteSelection();
    }

    //创建节点
    private void CreateNode(Type type)
    {
        Node node = tree.CreateNode(type);
        CreateNodeView(node);
    }

    private void CreateNodeView(Node node)
    {
        NodeView nodeView = new NodeView(node);
        nodeView.OnNodeSelected = OnNodeSelected;
        AddElement(nodeView);
    }

3、设置节点元素输出端可连接端口


    public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
    {
        return ports.ToList().Where(
            endpost => endpost.direction != startPort.direction 
            && endpost.node != startPort.node).ToList();
    }

4、打开或者重新展示已有内容


    internal void PopulateView(NodeTree tree)
    {
        this.tree = tree;
        graphViewChanged -= OnGraphViewChange;
        DeleteElements(graphElements.ToList());
        graphViewChanged += OnGraphViewChange;
        tree.nodes.ForEach(n => CreateNodeView(n));
        tree.nodes.ForEach(n =>
        {
            var children = tree.GetChildren(n);
            children.ForEach(c =>
            {
                NodeView parentView = FindNodeView(n);
                NodeView childView = FindNodeView(c);
                Edge edge = parentView.output.ConnectTo(childView.input);
                AddElement(edge);
            });
        });
    }

5、当节点区域元素改变时,实现对应逻辑数据的修改

该方法在打开或展现时注册事件


    private GraphViewChange OnGraphViewChange(GraphViewChange graphViewChange)
    {
        if(graphViewChange.elementsToRemove != null)
        {
            graphViewChange.elementsToRemove.ForEach(elem => { 
                NodeView nodeview = elem as NodeView;
                if(nodeview != null)
                {
                    tree.DeleteNode(nodeview.node);
                }
                Edge edge = elem as Edge;
                if(edge != null)
                {
                    NodeView parentView = edge.output.node as NodeView;
                    NodeView childView = edge.input.node as NodeView;
                    tree.RemoveChild(parentView.node, childView.node);
                }
            });
        }

        if(graphViewChange.edgesToCreate != null)
        {
            graphViewChange.edgesToCreate.ForEach(edge =>
            {
                NodeView parentView = edge.output.node as NodeView;
                NodeView childView = edge.input.node as NodeView;
                tree.AddChild(parentView.node, childView.node);
            });
        }
        return graphViewChange;
    }

6、完整代码

运行时代码Runtime Code

6.1 Node

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class Node : ScriptableObject
{
    public enum State { Running, Waiting}

    public State state = State.Waiting;
    public bool started = false;
    public List<Node> children = new List<Node>();

    [HideInInspector] public string guid;
    [HideInInspector] public Vector2 position;

    public Node OnUpdate()
    {
        if(!started)
        {
            OnStart();
            started = true;
        }
        Node currentNode = LogicUpdate();
        if(state != State.Running)
        {
            OnStop();
            started = false;
        }
        return currentNode;
    }

    public abstract Node LogicUpdate();

    public abstract void OnStart();

    public abstract void OnStop();

}

6.2 NormalNode

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class NormalNode : Node
{
    [TextArea]
    public string dialogueContent;

    public override Node LogicUpdate()
    {
        // 判断进入下一节点条件成功时 需将节点状态改为非运行中 且 返回对应子节点
        if (Input.GetKeyDown(KeyCode.Space))
        {
            state = State.Waiting;
            if (children.Count > 0)
            {
                children[0].state = State.Running;
                return children[0];
            }
        }
        return this;
    }
    public override void OnStart()
    {
        Debug.Log(dialogueContent);
    }

    public override void OnStop()
    {
        Debug.Log("OnStop");
    }
}

6.3 NodeTree

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[CreateAssetMenu]
public class NodeTree : ScriptableObject
{
    public Node rootNode;
    public Node runningNode;
    public Node.State treeState = Node.State.Waiting;
    public List<Node> nodes = new List<Node>();

    public virtual void Update()
    {
        if(treeState == Node.State.Running && runningNode.state == Node.State.Running)
        {
            runningNode = runningNode.OnUpdate();
        }
    }

    /// <summary>
    /// 对话树开始的触发方法
    /// </summary>
    public virtual void OnTreeStart()
    {
        treeState = Node.State.Running;
        runningNode.state = Node.State.Running;
    }

    /// <summary>
    /// 对话树结束的触发方法
    /// </summary>
    public void OnTreeEnd()
    {
        treeState = Node.State.Waiting;
    }

#if UNITY_EDITOR
    public Node CreateNode(System.Type type)
    {
        Node node = ScriptableObject.CreateInstance(type) as Node;
        node.name = type.Name;
        node.guid = GUID.Generate().ToString();
        nodes.Add(node);
        if (!Application.isPlaying)
        {
            AssetDatabase.AddObjectToAsset(node, this);
        }
        AssetDatabase.SaveAssets();

        return node;
    }

    public Node DeleteNode(Node node)
    {
        nodes.Remove(node);
        AssetDatabase.RemoveObjectFromAsset(node);
        AssetDatabase.SaveAssets();
        return node;
    }

    public void RemoveChild(Node parent, Node child)
    {
        parent.children.Remove(child);
    }

    public void AddChild(Node parent, Node child)
    {
        parent.children.Add(child);
    }

    public List<Node> GetChildren(Node parent)
    {
        return parent.children;
    }
#endif
}

6.4 NodeTreeRunner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NodeTreeRunner : MonoBehaviour
{
    public NodeTree tree;
     
    void Start()
    {
        
    }
     
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.P))
        {
            tree.OnTreeStart();
        }
        if(tree != null && tree.treeState == Node.State.Running)
        {
            tree.Update();
        }
        if(Input.GetKeyDown(KeyCode.D))
        {
            tree.OnTreeEnd();
        }
    }
}

可视化编辑器代码 Editor

6.5 Uxml和Uss

NodeEditor Uxml

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
    <Style src="NodeEditor.uss" />
    <ui:VisualElement style="flex-grow: 1; flex-direction: row;">
        <ui:VisualElement name="LeftDiv" style="flex-grow: 0.3;">
            <ui:Label text="Inspector" display-tooltip-when-elided="true" name="Inspector" style="font-size: 15px; -unity-font-style: bold;" />
            <uie:ObjectField label="NodeTree" name="NodeTree" style="flex-grow: 0; flex-shrink: 0; min-width: auto; align-items: stretch; flex-wrap: nowrap; flex-direction: row; width: auto; max-width: none;" />
            <InspectorViewer style="flex-grow: 1;" />
        </ui:VisualElement>
        <ui:VisualElement name="RightDiv" style="flex-grow: 0.7;">
            <ui:Label text="NodeTreeVirwer" display-tooltip-when-elided="true" name="NodeTreeVirwer" style="-unity-font-style: bold; font-size: 15px;" />
            <NodeTreeViewer focusable="true" style="flex-grow: 1;" />
        </ui:VisualElement>
    </ui:VisualElement>
</ui:UXML>

NodeTreeViewer Uss

GridBackground{
    --grid-background-color: rgb(40,40,40);
    --line-color: rgba(193,196,192,0.1);
    --thick-line-color: rgba(193,196,192,0.1);
    --spacing: 15;
}

编辑器面板代码

6.6 NodeEdtor

using System;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;


public class NodeEditor : EditorWindow
{
    public NodeTreeViewer nodeTreeViewer;
    public InspectorViewer inspectorViewer;
    public ObjectField nodeTreeObj;

    [MenuItem("MyWindows/NodeEditor")]
    public static void ShowExample()
    {
        NodeEditor wnd = GetWindow<NodeEditor>();
        wnd.titleContent = new GUIContent("NodeEditor");
    }

    public void CreateGUI()
    {
        // Each editor window contains a root VisualElement object
        VisualElement root = rootVisualElement;


        // Import UXML
        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/NodeEditor/Editor/UI/NodeEditor.uxml");
        visualTree.CloneTree(root);

        var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/NodeEditor/Editor/UI/NodeEditor.uss");
        root.styleSheets.Add(styleSheet);
        nodeTreeViewer = root.Q<NodeTreeViewer>();
        inspectorViewer = root.Q<InspectorViewer>();
        nodeTreeObj = root.Q("NodeTree") as ObjectField;
        nodeTreeObj.objectType = typeof(NodeTree);
        nodeTreeViewer.OnNodeSelected = OnNodeSelectionChanged;
    }

    private void OnNodeSelectionChanged(NodeView view)
    {
        inspectorViewer.UpdateSelection(view.node);
    }

    private void OnSelectionChange()
    {
        NodeTree tree = Selection.activeObject as NodeTree;
        if (tree)
        {
            nodeTreeViewer.PopulateView(tree);
            nodeTreeObj.value = tree;
        }
        else
        {
            nodeTreeViewer.CloseNodeTreeViewer();
            nodeTreeObj.value = null;
        }
    }

}

6.7 NodeTreeViewer 

using BehaviorDesigner.Runtime.Tasks.Unity.UnityInput;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;

public class NodeTreeViewer : GraphView
{
    public new class UxmlFactory : UxmlFactory<NodeTreeViewer, UxmlTraits> { }

    public NodeTree tree;
    public Action<NodeView> OnNodeSelected;

    private Vector2 curMousePos;
    ContentZoomer contentZoomer;
    ContentDragger contentDragger;

    public NodeTreeViewer()
    {
        Insert(0, new GridBackground());
        contentZoomer = new ContentZoomer();
        this.AddManipulator(contentZoomer);
        contentDragger = new ContentDragger();
        this.AddManipulator(contentDragger);
        this.AddManipulator(new SelectionDragger());
        this.AddManipulator(new RectangleSelector());
        var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/NodeEditor/Editor/UI/NodeTreeViewer.uss");
        styleSheets.Add(styleSheet);

        this.RegisterCallback<MouseDownEvent>(OnMouseDown);

    }

    private void OnMouseDown(MouseDownEvent evt)
    {
        Debug.Log(evt.localMousePosition);
        curMousePos = evt.localMousePosition;
        Debug.Log(contentZoomer.scaleStep);
        Debug.Log(contentZoomer.referenceScale);
        //Debug.Log(contentDragger.p)
    }

    public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
    {
        var types = TypeCache.GetTypesDerivedFrom<Node>();
        foreach (var type in types)
        {
            evt.menu.AppendAction($"创建节点/{type.Name}", a => CreateNode(type));
        }
        evt.menu.AppendAction("删除选中元素", DeleteSelecteNode);
    }

    private void DeleteSelecteNode(DropdownMenuAction action)
    {
        DeleteSelection();
    }

    private void CreateNode(Type type)
    {
        Node node = tree.CreateNode(type);
        node.position = curMousePos;
        CreateNodeView(node);
    }

    private void CreateNodeView(Node node)
    {
        NodeView nodeView = new NodeView(node);
        nodeView.OnNodeSelected = OnNodeSelected;
        AddElement(nodeView);
    }

    internal void PopulateView(NodeTree tree)
    {
        this.tree = tree;
        graphViewChanged -= OnGraphViewChange;
        DeleteElements(graphElements.ToList());
        graphViewChanged += OnGraphViewChange;
        tree.nodes.ForEach(n => CreateNodeView(n));
        tree.nodes.ForEach(n =>
        {
            var children = tree.GetChildren(n);
            children.ForEach(c =>
            {
                NodeView parentView = FindNodeView(n);
                NodeView childView = FindNodeView(c);
                Edge edge = parentView.output.ConnectTo(childView.input);
                AddElement(edge);
            });
        });
    }

    public void CloseNodeTreeViewer()
    {
        this.tree = null;
        graphViewChanged -= OnGraphViewChange;
        DeleteElements(graphElements.ToList());
    }

    private GraphViewChange OnGraphViewChange(GraphViewChange graphViewChange)
    {
        if(graphViewChange.elementsToRemove != null)
        {
            graphViewChange.elementsToRemove.ForEach(elem => { 
                NodeView nodeview = elem as NodeView;
                if(nodeview != null)
                {
                    tree.DeleteNode(nodeview.node);
                }
                Edge edge = elem as Edge;
                if(edge != null)
                {
                    NodeView parentView = edge.output.node as NodeView;
                    NodeView childView = edge.input.node as NodeView;
                    tree.RemoveChild(parentView.node, childView.node);
                }
            });
        }

        if(graphViewChange.edgesToCreate != null)
        {
            graphViewChange.edgesToCreate.ForEach(edge =>
            {
                NodeView parentView = edge.output.node as NodeView;
                NodeView childView = edge.input.node as NodeView;
                tree.AddChild(parentView.node, childView.node);
            });
        }
        return graphViewChange;
    }

    NodeView FindNodeView(Node node)
    {
        return GetNodeByGuid(node.guid) as NodeView;
    }

    public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
    {
        return ports.ToList().Where(
            endpost => endpost.direction != startPort.direction 
            && endpost.node != startPort.node).ToList();
    }

}

6.8 NodeView

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;

public class NodeView : UnityEditor.Experimental.GraphView.Node
{
    public Node node;
    public Port input;
    public Port output;
    public Action<NodeView> OnNodeSelected;
    public NodeView(Node node)
    {
        this.node = node;
        this.title = node.name;
        this.viewDataKey = node.guid;
        style.left = node.position.x;
        style.top = node.position.y;
        CreateInputPorts();
        CreateOutputPorts();
    }

    private void CreateInputPorts()
    {
        input = InstantiatePort(Orientation.Vertical, Direction.Input, Port.Capacity.Multi, typeof(bool));
        if(input != null )
        {
            input.portName = "input";
            inputContainer.Add(input);
        }
    }

    private void CreateOutputPorts()
    {
        output = InstantiatePort(Orientation.Vertical, Direction.Output, Port.Capacity.Multi, typeof(bool));
        if (output != null)
        {
            output.portName = "output";
            outputContainer.Add(output);
        }
    }

    public override void OnSelected()
    {
        base.OnSelected();
        if( OnNodeSelected != null )
        {
            OnNodeSelected?.Invoke(this);
        }
    }

    public override void SetPosition(Rect newPos)
    {
        Debug.Log(newPos);
        base.SetPosition(newPos);
        node.position.x = newPos.xMin;
        node.position.y = newPos.yMin;
    }

}

6.9 InspectorViewer

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public class InspectorViewer : VisualElement
{
    public new class UxmlFactory : UxmlFactory<InspectorViewer, UxmlTraits> { }

    Editor editor;

    public InspectorViewer()
    {
        //this.AddManipulator(new drag)
    }

    internal void UpdateSelection(Node node)
    {
        Clear();
        UnityEngine.Object.DestroyImmediate(editor);
        editor = Editor.CreateEditor(node);
        IMGUIContainer container = new IMGUIContainer(() =>
        {
            if (editor.target)
            {
                editor.OnInspectorGUI();
            }
        });
        Add(container);
    }

}

【Unity UIToolkit】UIBuilder基础教程-制作简易的对话系统编辑器 3步教你玩转Unity编辑器扩展工具_unity uibuilder-CSDN博客

[Unity] GraphView 可视化节点的事件行为树(二) UI Toolkit介绍,制作事件行为树的UI_unity graphview-CSDN博客 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1958347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UnityShaderUI编辑器扩展

前言&#xff1a; 当我们在制作通用Shader的时候&#xff0c;避免不了许多参数混杂在一起&#xff0c;尽管在材质面板已经使用过Header标签来区分&#xff0c;但是较长的Shader参数就会导致冗余&#xff0c;功能块不够简约明了&#xff0c;如图&#xff1a; 对于Shader制作者来…

如何在 VPS 上安装和使用 VirtualMin

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 关于 Virtualmin Virtualmin 是 Webmin 的一个模块&#xff0c;允许对&#xff08;多个&#xff09;虚拟专用服务器进行广泛的管理。您…

二进制部署k8s集群之master节点和etcd数据库集群(上)

目录 1.操作系统初始化配置 2.升级Linux内核 3.部署docker引擎 4.部署etcd集群 4.1 了解etcdctl工具对etcd做增删改查 4.2 通过etcdctl工具实现数据库的备份和恢复 5.部署Master组件 6.部署 Worker Node 组件 二进制搭建 Kubernetes v1.20 k8s集群master01&#xff1a…

230.信号量

信号量是一种用于多线程同步的机制&#xff0c;可以控制对共享资源的访问。信号量的基本概念是使用计数器来控制多个线程对共享资源的访问。信号量可以分为两类&#xff1a;计数信号量&#xff08;Counting Semaphore&#xff09;和二进制信号量&#xff08;Binary Semaphore&a…

项目风险管理:从理论到实践的探索

项目风险管理&#xff1a;从理论到实践的探索 前言一、项目风险识别二、项目风险应对策略三、综合应对策略结语 前言 在当今快速变化的商业环境中&#xff0c;项目管理已成为组织实现目标的关键工具。然而&#xff0c;项目的成功往往伴随着各种不确定性和潜在风险。有效的风险管…

JCR一区级 | Matlab实现SO-Transformer-LSTM多变量回归预测(蛇群算法优化)

JCR一区级 | Matlab实现SO-Transformer-LSTM多变量回归预测&#xff08;蛇群算法优化&#xff09; 目录 JCR一区级 | Matlab实现SO-Transformer-LSTM多变量回归预测&#xff08;蛇群算法优化&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.【JCR一区级】M…

Oracle基础-SQL99标准的表连接方法

SELECT * FROM T_NUM CROSS JOIN T_GROUP; --笛卡尔积 ALTER TABLE T_GROUP RENAME COLUMN GID TO ID; --修改字段名 SELECT * FROM T_NUM NATURAL JOIN T_GROUP; --自然连接 会根据两表同名字段或者主外键自动关联 SELECT * FROM T_NUM JOIN T_GROUP USING(ID); --USING连接&…

正余弦算法作者又提出新算法!徒步优化算法(HOA)-2024年一区顶刊新算法-公式原理详解与性能测评 Matlab代码免费获取

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原理简介 算法伪代码 性能测评 参考文献 …

oracle语法介绍

Oracle数据库是关系型数据库管理系统之一&#xff0c;其SQL语法遵循标准的SQL规范&#xff0c;但也有一些自己的扩展。以下是一些Oracle SQL语法的基本示例&#xff1a; 1.选择数据&#xff1a; SELECT * FROM my_table; 1.插入数据&#xff1a; INSERT INTO my_table (colum…

Vue 3 中使用 InMap 绘制热力图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 Vue 3 中使用 InMap 绘制热力图 应用场景介绍 InMap 是一款强大的地图组件库&#xff0c;它提供了一系列丰富的可视化功能&#xff0c;包括热力图。热力图可以将数据点在地图上以颜色编码的方式可视化&#x…

NGINX项目实战

一、nginx四层代理 部署支持4层TCP/UDP代理的Nginx服务器 部署nginx服务器 编译安装必须要使用--with-stream参数开启4层代理模块。 [rootproxy ~]# rm -rf /usr/local/nginx/ #清理环境 [rootproxy nginx-1.16.1]# ./configure --with-http_ssl_module --with-stream #开…

医疗器械产品没有互联网连接,就不适用于网络安全要求吗?

医疗器械产品是否不适用于网络安全要求&#xff0c;需要考虑产品是否具有网络连接功能以进行电子数据交换或远程控制&#xff0c;以及是否采用储存媒介进行电子数据交换。详细解析如下&#xff1a; 一、医疗器械的网络安全要求不仅限于互联网连接 数据交换接口&#xff1a;医疗…

这才是 PHP 高性能框架 Workerman 的立命之本

大家好&#xff0c;我是码农先森。 在这个大家都崇尚高性能的时代&#xff0c;程序员的谈笑间句句都离不开高性能&#xff0c;仿佛嘴角边不挂着「高性能」三个字都会显得自己很 Low&#xff0c;其中众所皆知的 Nginx 就是高性能的代表。有些朋友可能连什么是高性能都不一定理解…

【SPIE独立出版:高录用、快检索】第四届通信、网络与物联网国际学术会议 (CNIoT 2024,8月30-9月1)

为了促进通信、计算机和控制等领域专家学者跨界交流与合作&#xff0c;打造最前沿的交流平台&#xff0c;第四届通信、网络与物联网国际学术会议 (CNIoT 2024&#xff09;将涉及通信、网络、物联网、IT能量感知技术、人工智能应用等领域。 会议将为专注于该研究领域的国内外优秀…

一键切换阿里yum源(包括其他系统repo镜像查找方法)

一键切换阿里yum源 示例命令其他系统repo镜像GitHub文档 示例命令 # 备份旧源 mv CentOS-Base.repo CentOS-Base.repo.bak # 添加新源(阿里镜像源) wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo其他系统repo镜像 这里的示例是用…

RT-DETR:DETRs Beat YOLOs on Real-time Object Detection (CVPR2024)

DETRs Beat YOLOs on Real-time Object Detection 论文链接&#xff1a;http://arxiv.org/abs/2304.08069 代码链接&#xff1a;https://github.com/lyuwenyu/RT-DETR https://github.com/ultralytics/ultralytics/tree/main/ultralytics/models/rtdetr&#xff08;已集成到Y…

2024.7.29 作业

1> 写一个日志文件&#xff0c;将程序启动后&#xff0c;每一秒的时间写入到文件中 #include <myhead.h> int main(int argc,const char *argv[]) {FILE *fp NULL;if((fpfopen("./log.txt","r"))NULL) {perror("open error1");return…

使用 Python 实现计算交并比(IoU)的代码示例:

两个矩形框的交集/并集 IOU(A)/(ABC) box_areas(box[2]-box[0])*(box[3]-box[1])boxes_areas(box[:,2]-box[:,0])*(box[:,3]-box[:,1])l_xtorch.maximum(box[0],boxes[:,0])l_ytorch.maximum(box[1],boxes[:,1])r_xtorch.minimum(box[2],boxes[:2])r_ytorch.minimum(box[3],box…

SpringCloud+Vue3主子表插入数据(芋道)

目的&#xff1a;多表联查获取到每个班级里面所有的学生上课的信息。点击消课插入到消课主表和消课子表&#xff0c;主表记录班级信息&#xff0c;消课人员信息&#xff0c;上课时间。子表记录上课学员的信息&#xff0c;学员姓名、手机号、班级名称、班级类型、上课时间、老师…

7月29(信息差)

&#x1f30d;最强模型 Llama 3.1 如期而至&#xff01;扎克伯格最新访谈&#xff1a;Llama 会成为 AI 界的 Linux &#x1f384;谷歌AlphaProof攻克国际奥赛数学题 https://www.51cto.com/article/793632.html ✨SearchGPT第一波评测来了&#xff01;响应速度超快还没广告&…