VTK交互-vtkBoxWidget2

news2024/10/5 15:33:59

VTK交互Widget

widget包含两个重要的组成部分:Interaction和Representation.
Interaction是一些名叫vtk*Widget的类(比如vtkBoxWidget2)。它包含了交互的所有选项和事件处理。
Representation是显示并与之交互的一类对象,以名叫vtk*Representation.

在窗口中实现自己的小部件,如果有交互,就要写自己的Representation和Widget。可以参考vtk已有的widget。
vtk已经实现的Widget如下图
在这里插入图片描述

在这里插入图片描述

由上图可知Widget基类是vtkAbstracWidget,它定义小部件/小部件表示的API。vtkAbstractWidget定义了一个API并实现了所有使用交互/表示设计的widget所共有的方法。在这个设计中,术语交互是指小部件中执行事件处理的部分,而表示则对应于用来表示小部件的vtkProp(或子类vtkWidgetRepresentation)。vtkAbstractWidget还实现了一些所有子类共有的方法。

vtkAbstractWidget 提供对 vtkWidgetEventTranslator 的访问。 此类负责将 VTK 事件(在 vtkCommand.h 中定义)转换为小部件事件(在 vtkWidgetEvent.h 中定义)。 可以操作此类,以便将不同的 VTK 事件映射到小部件事件,从而允许修改事件绑定。 vtkAbstractWidget 的每个子类都定义了它响应的事件。

vtkAbstractWidget 派生自 vtkInteractorObserver。vtkInteractorObserver是一个抽象的超类,用于观察由vtkRenderWindowInteractor调用的事件的子类。这些子类通常是像3D部件这样的东西;与场景中的演员交互的对象,或交互地探测场景的信息。

vtkInteractorObserver定义了SetInteractor()方法,并启用和禁用了vtkInteractorObserver对事件的处理。使用EnabledOn()或SetEnabled(1)方法来打开交互器观察器,使用EnabledOff()或SetEnabled(0)方法来关闭交互器。初始值为0。

为了支持对对象的交互式操作,这个类(和子类)调用了StartInteractionEvent、InteractionEvent和EndInteractionEvent等事件。当vtkInteractorObserver进入一个需要快速反应的状态时,这些事件被调用:鼠标运动等。例如,这些事件可以用来设置所需的更新帧率(StartInteractionEvent),操作数据或更新管道(InteractionEvent),并将所需的帧率设置为正常值(EndInteractionEvent)。另外两个事件,EnableEvent和DisableEvent,在交互器观察者被启用或禁用时被调用。

所以窗口小部件Widget类本质就是一个观察者监听来自Interactor的事件
在这里插入图片描述

由上图可知vtkWidgetRepresentation的基类是vtkProp,vtkActor2D的基类是vtkWidgetRepresentation是抽象类定义了小部件和小部件表示类之间的接口

用于定义 API 并部分实现不同类型的小部件的表示。小部件表示(即 vtkWidgetRepresentation 的子类)是一种 vtkProp这意味着它们可以像任何其他 vtkActor 一样与嵌入场景中的 vtkRenderer 端相关联。 但是,vtkWidgetRepresentation 还定义了一个 API,使其能够与子类 vtkAbstractWidget 配对,这意味着它可以由小部件驱动,在小部件响应注册事件时用于表示小部件。

此处定义的 API 应被视为实现小部件和小部件表示的指南。 小部件行为很复杂,表示响应已注册小部件事件的方式也很复杂,因此 API 可能因小部件而异,以反映这种复杂性。

创建交互的步骤

虽然每个Widget都提供了不同的功能以及不同的API,但是,Widget的创建以及使用基本都是类似的。创建Widget的一般步骤如下:

  1. 实例化Widget;
  2. 指定渲染窗口交互器。Widget可以通过它来监听用户事件。
  3. 必要时使用观察者/命令模式创建回调函数。与widget交互时,它会调用一些通用的VTK事件(94个事件列表),如StartInteractionEvent、InteractionEvent、EndInteractionEvent。用户通过监听这些事件并作出响应,从而可以更新数据、可视化参数或者应用程序的用户图形界面。
  4. 创建合适的几何表达实体。并用SetRepresentation()函数把他与Widget关联起来,或者使用Widget默认的几何表达实体。
  5. 最后,必须激活Widget,使其在渲染场景中显示。默认情况下,按键用于激活Widget,使其可以再场景中可见。
    正如之前我们讨论的那样,如果对Widget默认的事件绑定不满意,需要根据自己习惯定义的事件绑定,可以使用VTKWidgetEventTranslator类。同样,也可以使用该类的RemoveTranslation()函数取消已经绑定的事件,具体操作如下:
    translator->RemoveTranslation(vtkCommand::LeftButtonPressEvent);
    translator->RemoveTranslation(vtkCommand::LeftButtonReleaseEvent);
    

如何使用vtkBoxWidget

设置Widget位置

 void PlaceWidget(double bounds[6]) override;

获取Box的polyData

void GetPolyData(vtkPolyData* pd);

polydata由6个四边形面和15个点组成。前八个点定义了八个角点顶点;接下来的六个定义了-x、+x、-y、+y、-z、+z面点;最后一点(15个点中的第15个点)定义了六面体的中心(参考上面我标注的图)。当调用InteractionEvent或EndInteractionEvent事件时,这些点值保证是最新的。用户提供vtkPolyData并向其中添加点和单元格。

Box的vtkTransform

virtual void GetTransform(vtkTransform* t);  
virtual void SetTransform(vtkTransform* t);

SetTransform设置获取表示长方体变换的线性变换矩阵信息。注意:转换与最初调用PlaceWidget的位置有关。此方法修改提供的变换。变换可用于控制vtkProp3D的位置,以及其他变换操作(例如vtkTransformorMPolyData)

获取Box的plane

void GetPlanes(vtkPlanes* planes);

GetPlanes方法可以获取描述由box小部件定义的隐式函数的平面。用户必须提供类vtkPlanes的实例。需要注意的是:vtkPlanes是vtkImplicitFunction的一个子类,这意味着各种过滤器都可以使用它来执行数据的剪裁、剪切和选择(可以反转平面法线的方向以启用InsideOut标志)

句柄属性

  • HandleProperty是句柄属性(小球就是句柄),可以设置选定和正常时控制柄的属性。
  • SelectedHandleProperty是当前被选中的句柄属性。
  • FaceProperty是面属性(长方体的面),可以设置选定面和法线时面的特性。
  • SelectedFaceProperty是当前被选中的面属性。
  • OutlineProperty是轮廓属性(外边框的轮廓),可以设置被选中的和正常时轮廓的属性。
  • SelectedOutlineProperty是当前被选中的轮廓属性。
vtkGetObjectMacro(HandleProperty, vtkProperty);
vtkGetObjectMacro(SelectedHandleProperty, vtkProperty);
vtkGetObjectMacro(FaceProperty, vtkProperty);
vtkGetObjectMacro(SelectedFaceProperty, vtkProperty);
vtkGetObjectMacro(OutlineProperty, vtkProperty);
vtkGetObjectMacro(SelectedOutlineProperty, vtkProperty);

控制句柄(表面上的小球体)的显示

void HandlesOn();
void HandlesOff();

控制功能变量

TranslationEnabled/ScalingEnabled/RotationEnabled 用来控制小部件的行为,可以启用和禁用平移、旋转和缩放的行为。

vtkSetMacro(TranslationEnabled, vtkTypeBool);
vtkGetMacro(TranslationEnabled, vtkTypeBool);
vtkBooleanMacro(TranslationEnabled, vtkTypeBool);
vtkSetMacro(ScalingEnabled, vtkTypeBool);
vtkGetMacro(ScalingEnabled, vtkTypeBool);
vtkBooleanMacro(ScalingEnabled, vtkTypeBool);
vtkSetMacro(RotationEnabled, vtkTypeBool);
vtkGetMacro(RotationEnabled, vtkTypeBool);
vtkBooleanMacro(RotationEnabled, vtkTypeBool);

vtkBoxWidget2 相关源码分析

vtkBoxWidget2构造函数

构造函数主要定义了widget的事件,并将VTK事件翻译成Widget事件,从下面的代码可以看出使用SetCallbackMethod将VTK消息与实际的操作函数联系起来SetCallbackMethod调用了vtkWidgetEventTranslator::SetTranslation()方法将VTK事件翻译成Widget事件。这种机制有点类似Qt里面的信号槽连接。

// Define widget events
  this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent, vtkEvent::NoModifier, 0,
    0, nullptr, vtkWidgetEvent::Select, this, vtkBoxWidget2::SelectAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonReleaseEvent, vtkEvent::NoModifier,
    0, 0, nullptr, vtkWidgetEvent::EndSelect, this, vtkBoxWidget2::EndSelectAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::MiddleButtonPressEvent,
    vtkWidgetEvent::Translate, this, vtkBoxWidget2::TranslateAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::MiddleButtonReleaseEvent,
    vtkWidgetEvent::EndTranslate, this, vtkBoxWidget2::EndSelectAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent,
    vtkEvent::ControlModifier, 0, 0, nullptr, vtkWidgetEvent::Translate, this,
    vtkBoxWidget2::TranslateAction);

事件处理函数

// These methods handle events
  static void SelectAction(vtkAbstractWidget*);
  static void EndSelectAction(vtkAbstractWidget*);
  static void TranslateAction(vtkAbstractWidget*);
  static void ScaleAction(vtkAbstractWidget*);
  static void MoveAction(vtkAbstractWidget*);
  static void SelectAction3D(vtkAbstractWidget*);
  static void EndSelectAction3D(vtkAbstractWidget*);
  static void MoveAction3D(vtkAbstractWidget*);
  static void StepAction3D(vtkAbstractWidget*);

vtkBoxRepresentation 相关代码分析

BoxWidget中15个点的顺序如下图所示,便于后面代码分析。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XJVk2Njn-1683711832364)(https://note.youdao.com/yws/res/32343/WEBRESOURCE75e8d6e859af96038582a32aa177995a)]
vtkBoxRepresentation的构造函数中主要初始化连接渲染Box的管道。如上图可知Box中有6个面,15条线段,15个点。

vtkBoxRepresentation中相关变量介绍如下


//交互box的状态控制状态定义
 enum
  {
    Outside = 0,
    MoveF0,
    MoveF1,
    MoveF2,
    MoveF3,
    MoveF4,
    MoveF5,
    Translating,
    Rotating,
    Scaling
  };


// 构建6个面变量
vtkActor* HexActor;
vtkPolyDataMapper* HexMapper;
vtkPolyData* HexPolyData;
vtkPoints* Points; // 8 corners; 6 faces; 1 center
double N[6][3];    // 6个面的方向。存储顺序是(-x,+x,-y,+y,-z,+z)

//被选中的六面体其中的一个面的相关变量
vtkActor* HexFace;
vtkPolyDataMapper* HexFaceMapper;
vtkPolyData* HexFacePolyData;

// Handle 15个点的相关变量
vtkActor** Handle;
vtkPolyDataMapper** HandleMapper;
vtkSphereSource** HandleGeometry;

// 单元拾取相关,也是交互重要环节之一。
vtkCellPicker* HandlePicker;
vtkCellPicker* HexPicker;
vtkActor* CurrentHandle;
int CurrentHexFace;
vtkCellPicker* LastPicker;

vtkBoxRepresentation中相关API



//获取包围盒
double* GetBounds() VTK_SIZEHINT(6) override;

//窗口交互
void WidgetInteraction(double e[2]) override;
//复杂的交互
void ComplexInteraction(vtkRenderWindowInteractor* iren, vtkAbstractWidget* widget,
unsigned long event, void* calldata) override;
//计算交互状态
int ComputeComplexInteractionState(vtkRenderWindowInteractor* iren, vtkAbstractWidget* widget,
unsigned long event, void* calldata, int modify = 0) override;
//结束交互状态
void EndComplexInteraction(vtkRenderWindowInteractor* iren, vtkAbstractWidget* widget,
unsigned long event, void* calldata) override;



// 帮助函数,也就是具体实现box平移,旋转,缩放的具体函数实现
virtual void Translate(const double* p1, const double* p2);
virtual void Scale(const double* p1, const double* p2, int X, int Y);
virtual void Rotate(int X, int Y, const double* p1, const double* p2, const double* vpn);
void MovePlusXFace(const double* p1, const double* p2);
void MoveMinusXFace(const double* p1, const double* p2);
void MovePlusYFace(const double* p1, const double* p2);
void MoveMinusYFace(const double* p1, const double* p2);
void MovePlusZFace(const double* p1, const double* p2);
void MoveMinusZFace(const double* p1, const double* p2);
void UpdatePose(const double* p1, const double* d1, const double* p2, const double* d2);

void MoveFace(const double* p1, const double* p2, const double* dir, double* x1, double* x2,
    double* x3, double* x4, double* x5);

Rotate 实现分析

void vtkBoxRepresentation::Rotate(
  int X, int Y, const double* p1, const double* p2, const double* vpn)
{
  double* pts = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(0);
  double* center = static_cast<vtkDoubleArray*>(this->Points->GetData())->GetPointer(3 * 14);
  double v[3];    // vector of motion
  double axis[3]; // axis of rotation
  double theta;   // rotation angle
  int i;

  v[0] = p2[0] - p1[0];
  v[1] = p2[1] - p1[1];
  v[2] = p2[2] - p1[2];

  // Create axis of rotation and angle of rotation
  vtkMath::Cross(vpn, v, axis);
  if (vtkMath::Normalize(axis) == 0.0)
  {
    return;
  }
  //根据移动的L2距离和屏幕的尺寸L2比例来确定旋转的角度
  const int* size = this->Renderer->GetSize();
  double l2 = (X - this->LastEventPosition[0]) * (X - this->LastEventPosition[0]) +
    (Y - this->LastEventPosition[1]) * (Y - this->LastEventPosition[1]);
  theta = 360.0 * sqrt(l2 / (size[0] * size[0] + size[1] * size[1]));

  // 旋转变换,VTK Transform的标准操作
  this->Transform->Identity();
  this->Transform->Translate(center[0], center[1], center[2]);
  this->Transform->RotateWXYZ(theta, axis);
  this->Transform->Translate(-center[0], -center[1], -center[2]);

  // 设置拐角点
  // 首先把Points中的点进行transform
  //得到新的点,并跟新
  vtkPoints* newPts = vtkPoints::New(VTK_DOUBLE);
  this->Transform->TransformPoints(this->Points, newPts);

  for (i = 0; i < 8; i++, pts += 3)
  {
    this->Points->SetPoint(i, newPts->GetPoint(i));
  }
  newPts->Delete();
  //根据这8个点去计算其他要设置的点,并更新
  this->PositionHandles();
}

vtkBoxWidget 例子

  • BoxWidget2.cxx
#include <vtkActor.h>
#include <vtkBoxRepresentation.h>
#include <vtkBoxWidget2.h>
#include <vtkCommand.h>
#include <vtkConeSource.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkTransform.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkAxesActor.h>
#include <vtkPlanes.h>

namespace {
class vtkBoxCallback : public vtkCommand
{
public:
  static vtkBoxCallback* New()
  {
    return new vtkBoxCallback;
  }

  vtkSmartPointer<vtkActor> m_actor;

  void SetActor(vtkSmartPointer<vtkActor> actor)
  {
    m_actor = actor;
  }

  virtual void Execute(vtkObject* caller, unsigned long, void*)
  {
    vtkSmartPointer<vtkBoxWidget2> boxWidget =
        dynamic_cast<vtkBoxWidget2*>(caller);

    vtkNew<vtkTransform> t;

    dynamic_cast<vtkBoxRepresentation*>(boxWidget->GetRepresentation())
        ->GetTransform(t);
    this->m_actor->SetUserTransform(t);
  }

  vtkBoxCallback()
  {
  }
};
} // namespace

int main(int vtkNotUsed(argc), char* vtkNotUsed(argv)[])
{
  vtkNew<vtkNamedColors> colors;

  // 显示坐标系的vtk组件
  vtkSmartPointer<vtkAxesActor> axes_actor = vtkSmartPointer<vtkAxesActor>::New();
  axes_actor->SetPosition(0, 0, 0);
  axes_actor->SetTotalLength(2, 2, 2);
  axes_actor->SetShaftType(0);
  axes_actor->SetCylinderRadius(0.02);



  vtkNew<vtkConeSource> coneSource;
  coneSource->SetHeight(1.5);

  vtkNew<vtkPolyDataMapper> mapper;
  mapper->SetInputConnection(coneSource->GetOutputPort());

  vtkNew<vtkActor> actor;
  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(colors->GetColor3d("BurlyWood").GetData());

  vtkNew<vtkRenderer> renderer;
  renderer->AddActor(actor);
  //renderer->SetBackground(colors->GetColor3d("Blue").GetData());
  renderer->SetBackground(colors->GetColor3d("Black").GetData());
  renderer->ResetCamera(); // Reposition camera so the whole scene is visible

  vtkNew<vtkRenderWindow> renderWindow;
  renderWindow->AddRenderer(renderer);
  renderWindow->SetWindowName("BoxWidget2");

  vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
  renderWindowInteractor->SetRenderWindow(renderWindow);

  // Use the "trackball camera" interactor style, rather than the default
  // "joystick camera"
  vtkNew<vtkInteractorStyleTrackballCamera> style;
  renderWindowInteractor->SetInteractorStyle(style);

  vtkNew<vtkBoxWidget2> boxWidget;
  boxWidget->SetInteractor(renderWindowInteractor);
  boxWidget->GetRepresentation()->SetPlaceFactor(1); // Default is 0.5
  boxWidget->GetRepresentation()->PlaceWidget(actor->GetBounds());
  vtkNew<vtkPlanes> planes;
  vtkBoxRepresentation::SafeDownCast(boxWidget->GetRepresentation())->GetPlanes(planes);

  // Set up a callback for the interactor to call so we can manipulate the actor
  vtkNew<vtkBoxCallback> boxCallback;
  boxCallback->SetActor(actor);
  boxWidget->AddObserver(vtkCommand::InteractionEvent, boxCallback);

  boxWidget->On();

  // 控制坐标系,使之随视角共同变化 
  vtkSmartPointer<vtkOrientationMarkerWidget> widget = vtkSmartPointer<vtkOrientationMarkerWidget>::New();
  widget->SetOrientationMarker(axes_actor);
  widget->SetInteractor(renderWindowInteractor);
  widget->On();

  renderWindow->Render();
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}


  • CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(BoxWidget2)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../../../bin)
set(VTK_DIR S:/VTK-build)

find_package(ITK REQUIRED)

IF(ITK_FOUND) 
    INCLUDE(${ITK_USE_FILE})

ELSE(ITK_FOUND) 
    MESSAGE(FATAL_ERROR 
            "ITK not found. Please set ITK_DIR.") 
ENDIF(ITK_FOUND)
#message("ITK_USE_FILE BoxWidget2: ${ITK_USE_FILE}")

find_package(VTK REQUIRED)

if (NOT VTK_FOUND)
  message("Skipping BoxWidget2: ${VTK_NOT_FOUND_MESSAGE}")
  return()
endif()
message (STATUS "VTK_VERSION: ${VTK_VERSION}")
if (VTK_VERSION VERSION_LESS "8.90.0")
  # old system
  include(${VTK_USE_FILE})
  add_executable(BoxWidget2 MACOSX_BUNDLE BoxWidget2.cxx )
  target_link_libraries(BoxWidget2 PRIVATE ${VTK_LIBRARIES})
else()
  # Prevent a "command line is too long" failure in Windows.
  set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
  add_executable(BoxWidget2 MACOSX_BUNDLE BoxWidget2.cxx )
  target_link_libraries(BoxWidget2 PRIVATE ${VTK_LIBRARIES} ${ITK_LIBRARIES})
  # vtk_module_autoinit is needed
  vtk_module_autoinit(
    TARGETS BoxWidget2
    MODULES ${VTK_LIBRARIES}
    )
endif()


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BEuKXMgz-1683711832364)(https://note.youdao.com/yws/res/32503/WEBRESOURCE32c330512a8e819ec3ebb13e00ab260a)]

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

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

相关文章

origin 拟合计算酶的Kcat Km 值

origin拟合计算Kcat Km值 横坐标为底物浓度&#xff0c;纵坐标为反应速率 全选X 与Y坐标数据&#xff0c;然后选择菜单栏Analysis: Fitting: Nonlinear Curve Fit&#xff1a;Open Dialog 在Setting&#xff1a;Function Selection页面内的Category选择Pharmacology, Functi…

计算机网络基础知识(三)—— 什么是OSI七层模型?

文章目录 00 | &#x1f6f8;发展史&#x1f6f8;01 | &#x1f6f8;OSI七层参考模型&#x1f6f8;02 | &#x1f6f8;OSI七层参考模型的信息流向&#x1f6f8; OSI七层模型是Open Systems Interconnection Reference Model的缩写&#xff0c;是由国际标准化组织&#xff08;IS…

vue3使用keep-alive组件,包含动态组件使用

vue3使用keep-alive组件&#xff0c;包含动态组件使用 本文目录 vue3使用keep-alive组件&#xff0c;包含动态组件使用组件不使用keep-alive组件中使用v-if切换component动态组件切换因注释导致的意外错误动态组件的使用完整示例 路由不使用keep-alive路由中使用keep-alive生命…

公司数字化转型,如何选择高效的知识管理工具?

随着企业数字化转型的加速&#xff0c;知识管理工具的重要性也日益凸显。好的知识管理工具可以帮助企业提高工作效率、降低成本、提高创新能力和竞争力。但是&#xff0c;市场上的知识管理工具繁多&#xff0c;如何选择高效的知识管理工具成为了企业面临的一大难题。本文将从以…

Jenkins 入门系列之Role-based Strategy配置Gitlab Group管理用户组

目录 背景步骤1. 安装插件2. 配置Gitlab Group3. 配置 Jenkins 授权策略4. 配置 Jenkins 角色与授权5. 验证 背景 版本 Jenkins Version&#xff1a;Jenkins 2.403Gitlab Version: Gitlab 15.6部署环境&#xff1a;群晖NAS Docker 部署JenkinsGitlab 上一篇文章Jenkins 入门…

HTML详解

HTML是什么 html是一门语言&#xff0c;所有的网页都是用它编写出来的。 他是一门超文本标记语言。可以定义图片&#xff0c;音频&#xff0c;视频等。由标签组成。 HTMl仅仅定义了网站的接口。 具体的表现还需要css来实现&#xff0c;也就是css让网页变得更加好看。 网页…

智能聊天机器人ChatGPT商业版

作为一个智能聊天机器人&#xff0c;我是由OpenAI开发的。目前&#xff0c;我的商业版需要通过OpenAI的合作伙伴计划进行许可和部署&#xff0c;以确保我被用于适当的商业用途。如果您对商业使用感兴趣&#xff0c;请联系OpenAI以获取更多信息。 智能聊天机器人是一种能够自…

如何优化golang gc

目录 一.理解GO GC机制 1.1GC的耗时 1.2堆大小对GC的影响 1.3GC算法 二 如何查看GC信息 2.1使用GODEBUG"gotrace1" 2.2 go tool trace 2.3 debug.ReadGCStats ​编辑2.4 runtime.ReadMemStats 三 GC优化技巧 2.1并发GC 一.理解GO GC机制 GO语言采用的是三…

学习网络安全的拦路虎!你遇到几个?

很多零基础的同学想要学习网络安全&#xff0c;前期会各种寻找学习资料。最后发现资料一大堆&#xff0c;但无从下手&#xff0c;于是千辛万苦收集的资料就去收藏夹吃灰了。开始学习的小伙伴们通常也会越学越迷茫&#xff0c;毕竟资料并不是完整的&#xff0c;而是东拼西凑出来…

Docker时区问题

背景 当前docker容器技术应用越来越广泛&#xff0c;但在启动容器后&#xff0c;容器内部的时间并不是东八区 Docker的基础镜像设置大多是UTC&#xff0c;也就是标准的UTC 时间&#xff0c;所以要简单的调整一下&#xff0c;变成中国标准时间CST(China Standard Time UTC8:0…

OpenCL编程指南-1.2OpenCL图形API

OpenCL与图形 OpenCL的出现是对GPCPU编程的一个响应。人们用GPU处理图形&#xff0c;并且开始使用GPU完成工作中的非图形部分。基于这种趋势&#xff0c;异构计算&#xff08;已经存在很长时间&#xff09;与图形发生冲突&#xff0c;因此迫切需要一个行业标准。 OpenCL一直与…

使用Onenote进行钓鱼攻击事件分析

以其中遇到的一个案例为例子进行展开分析: 1、使用钓鱼邮件文案.one文件附件 From: Bank Complaints <bankcomplaintshkmagov.com> Sent: Thursday, March 2, 2023 11:00 AMTo: Miles Mok XXXXSubject: [External Mail] xxxx Industry Development Survey Dear XXXX Lt…

SpringBoot+Canal+RabbitMQ实战

1. Canal简介 https://github.com/alibaba/canal 1.1 Canal工作原理 MySQL主备复制原理 MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events&#xff0c;可以通过 show binlog events 进行查看)MySQL slave 将 master 的 b…

中断-NVIC与EXTI外设详解(超全面)

✅作者简介&#xff1a;嵌入式入坑者&#xff0c;与大家一起加油&#xff0c;希望文章能够帮助各位&#xff01;&#xff01;&#xff01;&#xff01; &#x1f4c3;个人主页&#xff1a;rivencode的个人主页 &#x1f525;系列专栏&#xff1a;玩转STM32 &#x1f4ac;推荐一…

档案馆对于档案室档案库房内温度和湿度的控制要求

编辑搜图 请点击输入图片描述&#xff08;最多18字&#xff09; 01 纸质档案库的温湿度要求 用房名称温度&#xff08;℃&#xff09;相对湿度&#xff08;%&#xff09;纸质档案库14~2445~60 02 特殊档案库的温湿度要求 用房名称温度&#xff08;℃&#xff09;相对湿度&am…

Golang中的运算符

目录 运算符 算术运算符 代码案例&#xff1a; 关系运算符 代码案例&#xff1a; 逻辑运算符 代码案例&#xff1a; 位运算符 代码案例&#xff1a; 赋值运算符 代码案例&#xff1a; 其他运算符 运算符 算术运算符 Go语言中的算术运算符包括加、减、乘、除和取模…

【深入理解redis】数据结构

文章目录 动态字符串SDS字符串编码类型 intsetDictZipListZipList的连锁更新问题 QuickListSkipListRedisObjectStringListSet结构ZSETHash Redis 共有 5 种基本数据结构&#xff1a;String&#xff08;字符串&#xff09;、List&#xff08;列表&#xff09;、Set&#xff08;…

2023进销存财务软件哪个好?哪些适合中小商户使用?

对于开店的老板来说&#xff0c;门店的财务管理一直都是比较头疼的一件事&#xff0c;销售业绩人工统计困难&#xff0c;记账对账效率低且容易出错。 使用进销存财务软件可以有效的帮助门店解决财务管理问题&#xff0c;但市面上这么多进销存财务软件&#xff0c;哪些性价比较高…

Android编译优化之混淆配置

Android编译优化之混淆配置 背景 为了使用java8及后续java新版本的特性&#xff0c;Google增加了一步编译过程—脱糖&#xff08;desugaring&#xff09;&#xff0c;但这一步会导致更长的编译时间&#xff0c;这也是为什么Google会推出D8和R8编译器来优化编译速度。 什么是脱…

【C语言】扫雷游戏

这里写目录标题 前言1.初始化棋盘2.展示棋盘3.布置雷4.开始扫雷4.1判断输赢4.2扫雷时连续性展开4.3展示玩法 5.整体代码展示5.1 game.h头文件展示5.2 game.c源文件展示5.3 text.c源文件展示 所属专栏&#xff1a;C语言 博主首页&#xff1a;初阳785 代码托管&#xff1a;chuyan…