首页 > 其他分享 >折腾笔记[6]-使用rust绘制三维画面

折腾笔记[6]-使用rust绘制三维画面

时间:2025-01-18 23:44:56浏览次数:1  
标签:matrix 0.0 三维 笔记 three let new rust view

摘要

使用rust绘制界面;界面包含一个三维坐标轴,使用鼠标旋转坐标轴,左侧显示对应的旋转向量,四元数等信息.
Use Rust to draw the interface; the interface contains a three-dimensional coordinate axis, which can be rotated using the mouse, and the corresponding rotation vector, quaternion and other information are displayed on the left side.

关键词

rust;nalgebra;egui;three-d;

关键信息

[package]
name = "exp65-rust-ziglang-slambook2"
version = "0.1.0"
edition = "2021"

[dependencies]
nalgebra = { version = "0.33.2",features = ["rand"]}
rand = "0.8.5"
wgpu = "23.0.1"
winit = "0.30.8"

eframe = "0.30.0"
egui = { version = "0.30.0", features = [
    "default"
]}
egui_extras = {version = "0.30.0",features = ["default", "image"]}

three-d = {path = "./static/three-d" , features=["egui-gui"] }
three-d-asset = {version = "0.9",features = ["hdr", "http"] }

env_logger = { version = "0.11.6", default-features = false, features = [
    "auto-color",
    "humantime",
] }

原理简介

rust打印变量的类型

在Rust中,类型推断是一个强大的特性,但在某些情况下,编译器可能无法推断出具体的类型。你提供的两个代码片段就展示了这种情况。
第一个代码片段:

(|view_matrix| {
    let type_name = std::any::type_name::<_>(&view_matrix);
    println!("typeof view_matrix is {:?}", type_name);
})(&view_matrix);

在这个片段中,编译器无法推断出view_matrix的类型,因为它被用作一个闭包的参数。在这个上下文中,view_matrix的类型是未知的,因此编译器无法为std::any::type_name::<_>(&view_matrix)推断出具体的类型参数。
第二个代码片段:

fn type_name_of<T>(_: &T) -> &'static str {
    std::any::type_name::<T>()
}
(|view_matrix| println!("typeof view_matrix is {:?}", type_name_of(view_matrix)))(&view_matrix);

在这个片段中,type_name_of函数是一个泛型函数,它接受一个引用作为参数,并返回一个静态字符串。当调用type_name_of(view_matrix)时,编译器可以推断出T的类型,因为view_matrix被传递给了这个函数。这样,std::any::type_name::<T>()就可以正确地推断出T的类型。
总结来说,第一个代码片段中,编译器无法推断出view_matrix的类型,因为它被用作一个闭包的参数,且没有足够的信息来确定其类型。而在第二个代码片段中,通过使用泛型函数type_name_of,编译器可以推断出view_matrix的类型,因为函数的泛型参数T提供了所需的信息。

rust的交互界面GUI库:egui和three_d简介

[https://github.com/asny/three-d]
[https://www.egui.rs/#demo]
[https://github.com/emilk/egui]
egui(发音为“e-gooey”)是一个简单、快速且高度可移植的Rust即时模式GUI库。egui可以在网页、本地以及您喜欢的游戏引擎中运行。
egui旨在成为最容易使用的Rust GUI库,也是用Rust制作网页应用的最简单方式。
只要您能绘制纹理三角形,就可以使用egui,这意味着您可以轻松将其集成到您选择的游戏引擎中。
eframe是官方的egui框架,支持为Web、Linux、Mac、Windows和Android编写应用。
一个OpenGL/WebGL/OpenGL ES渲染器,旨在使图形简单化,同时仍具有高效绘制您想要的内容的能力。
three-d
适用于那些只想绘制东西的人和那些想避免繁琐设置但仍希望获得低级访问权限的人。
使得结合高级功能与自定义低级实现成为可能,例如自定义着色器。
尝试用几行简单的代码完成工作。
力求尽可能明确,以便对您来说没有意外——没有隐藏的魔法。
适用于桌面、网页和移动设备。
three-d可以用于例如:
数据可视化
图像处理
UI渲染
工具(2D或3D)
游戏(2D或3D)

egui (pronounced "e-gooey") is a simple, fast, and highly portable immediate mode GUI library for Rust. egui runs on the web, natively, and in your favorite game engine.

egui aims to be the easiest-to-use Rust GUI library, and the simplest way to make a web app in Rust.

egui can be used anywhere you can draw textured triangles, which means you can easily integrate it into your game engine of choice.

eframe is the official egui framework, which supports writing apps for Web, Linux, Mac, Windows, and Android.

A OpenGL/WebGL/OpenGL ES renderer which seeks to make graphics simple but still have the power to efficiently draw exactly what you want.

three-d

targets those who just want to draw something and those who want to avoid the tedious setup but still wants low-level access.
makes it possible to combine high-level features with custom low-level implementations for example custom shaders.
tries to do stuff in a few simple lines of code.
aims to be as explicit as possible so there is no surprises for you - no hidden magic.
targets desktop, web and mobile.
three-d can for example be used for

data visualization
image processing
UI rendering
tools (2D or 3D)
games (2D or 3D)

实现

原始代码:[https://github.com/gaoxiang12/slambook2/blob/master/ch3/visualizeGeometry/visualizeGeometry.cpp]

#include <iostream>
#include <iomanip>

using namespace std;

#include <Eigen/Core>
#include <Eigen/Geometry>

using namespace Eigen;

#include <pangolin/pangolin.h>

struct RotationMatrix {
  Matrix3d matrix = Matrix3d::Identity();
};

ostream &operator<<(ostream &out, const RotationMatrix &r) {
  out.setf(ios::fixed);
  Matrix3d matrix = r.matrix;
  out << '=';
  out << "[" << setprecision(2) << matrix(0, 0) << "," << matrix(0, 1) << "," << matrix(0, 2) << "],"
      << "[" << matrix(1, 0) << "," << matrix(1, 1) << "," << matrix(1, 2) << "],"
      << "[" << matrix(2, 0) << "," << matrix(2, 1) << "," << matrix(2, 2) << "]";
  return out;
}

istream &operator>>(istream &in, RotationMatrix &r) {
  return in;
}

struct TranslationVector {
  Vector3d trans = Vector3d(0, 0, 0);
};

ostream &operator<<(ostream &out, const TranslationVector &t) {
  out << "=[" << t.trans(0) << ',' << t.trans(1) << ',' << t.trans(2) << "]";
  return out;
}

istream &operator>>(istream &in, TranslationVector &t) {
  return in;
}

struct QuaternionDraw {
  Quaterniond q;
};

ostream &operator<<(ostream &out, const QuaternionDraw quat) {
  auto c = quat.q.coeffs();
  out << "=[" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << "]";
  return out;
}

istream &operator>>(istream &in, const QuaternionDraw quat) {
  return in;
}

int main(int argc, char **argv) {
  pangolin::CreateWindowAndBind("visualize geometry", 1000, 600);
  glEnable(GL_DEPTH_TEST);
  pangolin::OpenGlRenderState s_cam(
    pangolin::ProjectionMatrix(1000, 600, 420, 420, 500, 300, 0.1, 1000),
    pangolin::ModelViewLookAt(3, 3, 3, 0, 0, 0, pangolin::AxisY)
  );

  const int UI_WIDTH = 500;

  pangolin::View &d_cam = pangolin::CreateDisplay().
    SetBounds(0.0, 1.0, pangolin::Attach::Pix(UI_WIDTH), 1.0, -1000.0f / 600.0f).
    SetHandler(new pangolin::Handler3D(s_cam));

  // ui
  pangolin::Var<RotationMatrix> rotation_matrix("ui.R", RotationMatrix());
  pangolin::Var<TranslationVector> translation_vector("ui.t", TranslationVector());
  pangolin::Var<TranslationVector> euler_angles("ui.rpy", TranslationVector());
  pangolin::Var<QuaternionDraw> quaternion("ui.q", QuaternionDraw());
  pangolin::CreatePanel("ui").SetBounds(0.0, 1.0, 0.0, pangolin::Attach::Pix(UI_WIDTH));

  while (!pangolin::ShouldQuit()) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    d_cam.Activate(s_cam);

    pangolin::OpenGlMatrix matrix = s_cam.GetModelViewMatrix();
    Matrix<double, 4, 4> m = matrix;

    RotationMatrix R;
    for (int i = 0; i < 3; i++)
      for (int j = 0; j < 3; j++)
        R.matrix(i, j) = m(j, i);
    rotation_matrix = R;

    TranslationVector t;
    t.trans = Vector3d(m(0, 3), m(1, 3), m(2, 3));
    t.trans = -R.matrix * t.trans;
    translation_vector = t;

    TranslationVector euler;
    euler.trans = R.matrix.eulerAngles(2, 1, 0);
    euler_angles = euler;

    QuaternionDraw quat;
    quat.q = Quaterniond(R.matrix);
    quaternion = quat;

    glColor3f(1.0, 1.0, 1.0);

    pangolin::glDrawColouredCube();
    // draw the original axis
    glLineWidth(3);
    glColor3f(0.8f, 0.f, 0.f);
    glBegin(GL_LINES);
    glVertex3f(0, 0, 0);
    glVertex3f(10, 0, 0);
    glColor3f(0.f, 0.8f, 0.f);
    glVertex3f(0, 0, 0);
    glVertex3f(0, 10, 0);
    glColor3f(0.2f, 0.2f, 1.f);
    glVertex3f(0, 0, 0);
    glVertex3f(0, 0, 10);
    glEnd();

    pangolin::FinishFrame();
  }
}

注意:three-d库需要使用[https://github.com/asny/three-d]的最新版本,参考toml方式引用本地库文件.

#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_assignments)]
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 
#![allow(rustdoc::missing_crate_level_docs)]
#![allow(unsafe_code)]
#![allow(clippy::undocumented_unsafe_blocks)]

use nalgebra::{
    Matrix3, Vector3, UnitQuaternion, 
    Quaternion, Isometry3, Rotation3, UnitComplex, Rotation2, Unit,
    Translation3, Perspective3, Orthographic3, Vector4, Point3, Const,
    ArrayStorage, Matrix4, ViewStorage
};

// 绘图和界面库
use three_d::*; 
use three_d::egui::*;

use env_logger::init;

use std::fmt;
use std::sync::Arc;
use std::any::type_name;

// 1. 定义一个结构体,用于表示旋转矩阵
#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Default)]
struct RotationMatrix {
    matrix: Matrix3<f64>,
}

// 实现Display trait,以便输出旋转矩阵
impl fmt::Display for RotationMatrix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.matrix)
    }
}

// 2. 定义一个结构体,用于表示平移向量
#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Default)]
struct TranslationVector {
    trans: Vector3<f64>,
}
// 实现Display trait,以便输出平移向量
impl fmt::Display for TranslationVector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "=[{}, {}, {}]", self.trans.x, self.trans.y, self.trans.z)
    }
}
// 3. 定义一个结构体,用于表示四元数
#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Default)]
struct QuaternionDraw {
    q: UnitQuaternion<f64>,
}
// 实现Display trait,以便输出四元数
impl fmt::Display for QuaternionDraw {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let i = self.q.quaternion().i;
        let j = self.q.quaternion().j;
        let k = self.q.quaternion().k;
        let w = self.q.quaternion().w;
        write!(f, "=[{}, {}, {}, {}]", i, j, k, w)
    }
}

 /* start 测试 */ 
fn test() {
    // 创建一个单位旋转矩阵
    let rotation_matrix = RotationMatrix {
        matrix: Matrix3::identity(),
    };
    // 测试矩阵是否为单位矩阵
    assert_eq!(rotation_matrix.matrix, Matrix3::identity(), "The matrix should be the identity matrix.");
    // 测试矩阵的行列式是否为1
    assert_eq!(rotation_matrix.matrix.determinant(), 1.0, "The determinant of the identity matrix should be 1.");
    // 打印旋转矩阵
    println!("{}", rotation_matrix);

    // 创建一个平移向量
    let translation_vector = TranslationVector {
        trans: Vector3::new(1.0, 2.0, 3.0),
    };
    // 定义一个预期的平移向量
    let expected_translation_vector = TranslationVector {
        trans: Vector3::new(1.0, 2.0, 3.0),
    };
    // 测试平移向量是否相等
    assert_eq!(translation_vector, expected_translation_vector, "The translation vectors should be equal.");
    // 打印平移向量
    println!("{}", translation_vector);

    // 创建一个单位四元数
    let quaternion_draw = QuaternionDraw {
        q: UnitQuaternion::identity(),
    };
    // 定义一个预期的单位四元数
    let expected_quaternion_draw = QuaternionDraw {
        q: UnitQuaternion::identity(),
    };
    // 测试四元数是否相等
    assert_eq!(quaternion_draw, expected_quaternion_draw, "The quaternions should be equal.");
    // 打印四元数
    println!("{}", quaternion_draw);
}
/* end 测试 */

/* start 绘制界面和绘图 */
pub fn main() {
    let window = three_d::Window::new(WindowSettings {
        title: "Shapes!".to_string(),
        max_size: Some((1280, 720)),
        ..Default::default()
    })
    .unwrap();
    let context = window.gl();

    let mut camera = three_d::Camera::new_perspective(
        window.viewport(),
        vec3(5.0, 2.0, 2.5),
        vec3(0.0, 0.0, -0.5),
        vec3(0.0, 1.0, 0.0),
        degrees(45.0),
        0.1,
        1000.0,
    );
    let mut control = three_d::OrbitControl::new(camera.target(), 1.0, 100.0);

    /* start 绘制立体图形 */
    let mut sphere = three_d::Gm::new(
        three_d::Mesh::new(&context, &CpuMesh::sphere(16)),
        three_d::PhysicalMaterial::new_transparent(
            &context,
            &CpuMaterial {
                albedo: Srgba {
                    r: 255,
                    g: 0,
                    b: 0,
                    a: 200,
                },
                ..Default::default()
            },
        ),
    );
    sphere.set_transformation(Mat4::from_translation(vec3(0.0, 1.3, 0.0)) * Mat4::from_scale(0.2));
    let mut cylinder = three_d::Gm::new(
        three_d::Mesh::new(&context, &CpuMesh::cylinder(16)),
        three_d::PhysicalMaterial::new_transparent(
            &context,
            &CpuMaterial {
                albedo: Srgba {
                    r: 0,
                    g: 255,
                    b: 0,
                    a: 200,
                },
                ..Default::default()
            },
        ),
    );
    cylinder
        .set_transformation(Mat4::from_translation(vec3(1.3, 0.0, 0.0)) * Mat4::from_scale(0.2));
    let mut cube = three_d::Gm::new(
        three_d::Mesh::new(&context, &CpuMesh::cube()),
        three_d::PhysicalMaterial::new_transparent(
            &context,
            &CpuMaterial {
                albedo: Srgba {
                    r: 0,
                    g: 0,
                    b: 255,
                    a: 100,
                },
                ..Default::default()
            },
        ),
    );
    cube.set_transformation(Mat4::from_translation(vec3(0.0, 0.0, 1.3)) * Mat4::from_scale(0.2));
    let axes = three_d::Axes::new(&context, 0.1, 2.0);
    let bounding_box_sphere = Gm::new(
        BoundingBox::new(&context, sphere.aabb()),
        ColorMaterial {
            color: Srgba::BLACK,
            ..Default::default()
        },
    );
    let bounding_box_cube = three_d::Gm::new(
        three_d::BoundingBox::new(&context, cube.aabb()),
        ColorMaterial {
            color: Srgba::BLACK,
            ..Default::default()
        },
    );
    let bounding_box_cylinder = three_d::Gm::new(
        three_d::BoundingBox::new(&context, cylinder.aabb()),
        ColorMaterial {
            color: Srgba::BLACK,
            ..Default::default()
        },
    );

    let light0 = DirectionalLight::new(&context, 1.0, Srgba::WHITE, vec3(0.0, -0.5, -0.5));
    let light1 = DirectionalLight::new(&context, 1.0, Srgba::WHITE, vec3(0.0, 0.5, 0.5));
    /* end 绘制立体图形 */

    let mut gui = three_d::GUI::new(&context);
    // main loop
    window.render_loop(move |mut frame_input| {
        let mut panel_width = 0.0;
        gui.update(
            &mut frame_input.events,
            frame_input.accumulated_time,
            frame_input.viewport,
            frame_input.device_pixel_ratio,
            |gui_context| {

                SidePanel::left("side_panel").show(gui_context, |ui| {
                    ui.heading("Camera Pose");
                    // 显示相机的平移向量
                    let translation_vector = camera.position();
                    ui.label(format!("Translation Vector: {:?}", translation_vector));
                    // 获取相机的视图矩阵
                    let view_matrix = camera.view();

                    /* start 打印camera.view()返回值的数据类型 */
                    // fn type_name_of<T>(_: &T) -> &'static str {
                    //     std::any::type_name::<T>()
                    // }
                    // (|view_matrix| println!("typeof view_matrix is {:?}", type_name_of(view_matrix)))(&view_matrix);
                    /* end 打印camera.view()返回值的数据类型 */

                    // 从视图矩阵中提取旋转矩阵
                    // view_matrix:cgmath::Matrix4<f32>转为nal_view_matrix:nalgebra::Matrix4<f32>数据
                    let nal_view_matrix = nalgebra::Matrix4::new(
                        view_matrix.x.x, view_matrix.x.y, view_matrix.x.z, view_matrix.x.w,
                        view_matrix.y.x, view_matrix.y.y, view_matrix.y.z, view_matrix.y.w,
                        view_matrix.z.x, view_matrix.z.y, view_matrix.z.z, view_matrix.z.w,
                        view_matrix.w.x, view_matrix.w.y, view_matrix.w.z, view_matrix.w.w,
                    );
                    let rotation_matrix = nal_view_matrix.try_inverse().unwrap_or_else(|| Matrix4::identity());
                    // let rotation_matrix = nalgebra::Matrix4::<f64>::identity();
                    
                    // 从 rotation_matrix 中提取 3x3 的视图
                    let rotation_matrix_view = rotation_matrix.fixed_view::<3, 3>(0, 0);
                    // 创建一个新的 nalgebra::Matrix3<f32> 实例
                    let rotation_matrix3 = nalgebra::Matrix3::from(rotation_matrix_view);
                    ui.label(format!("Rotation Matrix: {:?}", rotation_matrix3));

                    // 从旋转矩阵中提取四元数
                    // let quaternion = Quaternion::new(1.0, 0.0, 0.0, 0.0); // 提供了合适的数值
                    // 注意:这里假设 rotation_matrix3 是一个纯旋转矩阵,没有平移部分
                    let unit_quaternion = UnitQuaternion::from_matrix(&rotation_matrix3);
                    ui.label(format!("Quaternion: {:?}", unit_quaternion));

                    // 从四元数中提取欧拉角
                    let euler_angles = unit_quaternion.euler_angles();
                    ui.label(format!("Euler Angles: {:?}", euler_angles));

                }); // end SidePanel show

                panel_width = gui_context.used_rect().width();
            }, // end gui_context

        ); // end gui.update

        // 更新相机视图
        camera.set_viewport(Viewport {
            x: (panel_width * frame_input.device_pixel_ratio) as i32,
            y: 0,
            width: frame_input.viewport.width
                - (panel_width * frame_input.device_pixel_ratio) as u32,
            height: frame_input.viewport.height,
        });
        control.handle_events(&mut camera, &mut frame_input.events);
        // 绘制场景
        frame_input
            .screen()
            .clear(ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0))
            .render(
                &camera,
                sphere
                    .into_iter()
                    .chain(&cylinder)
                    .chain(&cube)
                    .chain(&axes)
                    .chain(&bounding_box_sphere)
                    .chain(&bounding_box_cube)
                    .chain(&bounding_box_cylinder),
                &[&light0, &light1],
            )
            .write(|| gui.render())
            .unwrap();
        FrameOutput::default()


    });
}
/* end 绘制界面和绘图 */

效果

界面显示四元数

检查结果合理性

**总结性解决方案**
1. **翻译向量检查**
   - **数值**:`[4.5996685, 3.6870298, 1.3024255]`
   - **分析**:向量值在三维空间中大小适中,无极端值。
   - **结论**:翻译向量数值正确。
2. **旋转矩阵检查**
   - **矩阵**:
     \[
     \begin{bmatrix}
     0.3648478 & -0.5568863 & 0.74616593 \\
     0.0 & 0.8014093 & 0.59811616 \\
     -0.9310671 & -0.21822138 & 0.29239246 \\
     \end{bmatrix}
     \]
   - **正交性检查**:
     - 每行和每列的模长均接近1。
     - 不同行向量和列向量的点积接近0,满足正交条件。
   - **行列式检查**:
     - 计算得行列式约为1,符合旋转矩阵要求。
   - **结论**:旋转矩阵数值正确。
3. **四元数检查**
   - **数值**:`[0.26031038, -0.5348292, -0.17757763, 0.78400415]`
   - **模长检查**:
     - 模长计算为1,为单位四元数。
   - **与旋转矩阵对应性检查**:
     - 将四元数转换为旋转矩阵,发现与给定旋转矩阵不一致,特别是第一行第二列的元素不符。
   - **结论**:四元数可能有误。
4. **欧拉角检查**
   - **数值**:`(1.1161038, -0.8422845, -0.99080443)`(单位:弧度)
   - **范围分析**:
     - 滚转约 \(64^\circ\),俯仰约 \(-48^\circ\),偏航约 \(-56.8^\circ\),均在合理范围内。
   - **结论**:欧拉角数值合理。
**最终结论**
\[
\boxed{\text{翻译向量和旋转矩阵数值正确,四元数可能有误。}}
\]

标签:matrix,0.0,三维,笔记,three,let,new,rust,view
From: https://www.cnblogs.com/qsbye/p/18679035

相关文章

  • 运算放大器应用电路设计笔记(四)
    动态范围表示正常工作时最小振幅与最大振幅的范围。例如,最小振幅为-14v,最大振幅为+14v,则动态范围为±14v,也有用绝对值或有效值表示振幅,最大电压与最小电压之比为动态范围,也称为多少dB。这时,最大振幅由电源电压决定,最小振幅由噪声或失调电压决定。确保动态范围的最简单方法......
  • 数学笔记
    定义一个形如\(x=a+bi\)的数为复数。上式中的\(i\)为虚数单位,有\(i\cdoti=-1\)。两个复数\(x\)和\(y\)相等,当且仅当\(x_a=y_a\)且\(x_b=y_b\)。对于一个复数\(x\),我们称\(a\)为\(x\)的实部,\(b\)为\(x\)的虚部。当\(a=0\)时,称\(x\)为纯虚数。......
  • NixOS使用笔记
    官方源:https://channels.nixos.org/清华源:https://mirrors.tuna.tsinghua.edu.cn/nix-channels本文使用清华源。升级系统官方文档:https://nixos.org/manual/nixos/stable/#sec-upgrading比如升级到24.11,首先升级到#sudonix-channel--addhttps://channels.nixos.org/nixo......
  • [数据结构学习笔记16] 线性查找(Linear Search)
    查找算法是指从一个集合里比如数组,列表,树里查找我们想要的值。我们从最简单的线性查找开始。线性查找,就是遍历集合里的元素,查看是否有和我们想要查找的值相同的,有则查找成功,没有则查找失败。比如:5,8,6,9,1,7,3,2,4我们要找3,那从5开始依次往后,到了第7个(下标6),我们找到了3。如果我们要找......
  • 计数问题学习笔记
    基础差得死,整版讲课课件能看懂的就\(10\%\),所以过来补一补。数学那一块差不多,计划单开一个博客。分类整理以下吧。卡特兰数问题引入有一个大小为\(n\timesn\)的网格图,每次从\((x,y)\)只能走一步到\((x+1,y)\)或\((x,y+1)\),求不走到对角线即\(y=x\)下方,但可以触碰对......
  • base中TCP/IP基础学习笔记
    base中的网络模型的学习笔记一.关于TCP/IP网络模型引言对于同一台设备上的进程间通信,有很多种方式,有管道、消息队列、共享内存、信号等方式,对于不同设备上的进程间通信,就需要网络通信,设备是多样的,所以要兼容各种各样的设备,就协商出了一套通用的网络协议。网络协议是分层......
  • Pandas使用笔记
    个人学习笔记日期转换索引日期格式:2023-09-1215:00:00转换为:2023-09-12importpandasaspd#假设你的DataFrame名为df,索引是2023-09-1215:00:00#这里创建一个示例DataFrame用于演示data={'value':[1,2,3]}index=pd.to_datetime(['2023-09-1215:00:......
  • THREE.js学习笔记9——Materials
    这一小节主要学习材质材质用于为几何物理模型的每个可见像素添加颜色。Materialsareusedtoputacoloroneachvisiblepixelofthegeometries.决定每个像素颜色的算法是在程序中编写的,称为着色器。Three.js具有许多带有预制着色器的内置材料。Algorithmsthatdecid......
  • 黑马前端学习笔记(1)HTML5篇
    第一天目录第一天1、HTML定义2、标签语法3、HTML基本骨架4、标签的关系5、注释6、排版标签①标题标签②段落标签③换行和水平线标签④文本格式化标签7、图像标签①基本使用②属性8、路径①相对路径-从当前文件位置出发查找目标文件②绝对路径-从盘符出发查找......
  • 详解Rust 中 String 和 str 的用途与区别
    文章目录1.基本定义1.1String1.2str2.存储位置与内存模型2.1String2.2str3.用法与区别4.使用场景4.1使用String的场景4.2使用str的场景5.String和str的关系6.代码示例分析6.1从&str创建String6.2从String获取&str6.3拼接字符串6.4静态......