WebGL层次模型——单节点模型
目录
多个简单模型组成的复杂模型
层次结构模型
单关节模型
JointModel程序中模型的层次结构
示例程序(JointMode.js)
代码详解
绘制层次模型(draw())
程序效果
多个简单模型组成的复杂模型
绘制由多个小部件组成的复杂模型,最关键的问题是如何处理模型的整体移动,以及各个小部件间的相对移动。现在就来研究这个问题。首先,考虑一下人类的手臂:从肩部到指尖,包括上臂(肘以上)、前臂(肘以下)、手掌和手指,如下图所示。
手臂的每个部分可以围绕关节运动,如上图所示:
● 上臂可以绕肩关节旋转运动,并带动前臂、手掌和手指一起运动。
● 前臂可以绕肘关节运动,并带动手掌和手指一起运动,但不影响上臂。
● 手掌绕腕关节运动,并带动手指一起运动,但不影响上臂和前臂。
● 手指运动不影响上臂、前臂和手掌。
总之,当手臂的某个部位运动时,位于该部位以下的其他部位会随之一起运动,而位于该部位以上的其他部位不受影响。此外,这里的所有运动,都是围绕某个关节(肩关节、肘关节、腕关节、指关节)的转动。
层次结构模型
绘制机器人手臂这样一个复杂的模型,最常用的方法就是按照模型中各个部件的层次顺序,从高到低逐一绘制,并在每个关节上应用模型矩阵。比如,在图9.2中,肩关节、肘关节、腕关节,指关节都有各自的旋转矩阵。
注意,三维模型和现实中的人类或机器人不一样,它的部件并没有真正连接在一起。如果直接转动上臂,那么肘部以下的部分,包括前臂、手掌和手指,只会留在原地,这样手臂就断开了。所以,当上臂绕肩关节转动时,你需要在代码中实现“肘部以下部分跟随上臂转动”的逻辑。具体地,上臂绕肩关节转动了多少度,肘部以下的部分也应该绕肩关节转动多少度。
当情况较为简单时,实现“部件A转动带动部件B转动”可以很直接,只要对部件B也施以部件A的旋转矩阵即可。比如,使用模型矩阵使上臂绕肩关节转动30度,然后在绘制肘关节以下的各部位时,为它们施加同一个模型矩阵,也令其绕肩关节转动30度,如下图所示。这样,肘关节以下的部分就能自动跟随上臂转动了。
肘部以下部分随着上臂转动
如果情况更复杂一些,比如先使上臂绕肩关节转动30度,然后使前臂绕肘关节转动10度,那么对肘关节以下的部分,你就得先施加上臂绕肩关节转动30度的矩阵(可称为“肩关节模型矩阵”),然后再施加前臂绕肘关节转动10度的矩阵。将这两个矩阵相乘,其结果可称为“肘关节模型矩阵”,那么在绘制肘关节以下部分的时候,直接应用这个所谓的“肘关节模型矩阵”(而不考虑肩关节,因为肩关节的转动信息已经包含在该矩阵中了)作为模型矩阵就可以了。
按照上述方式编程,三维场景中的肩关节就能影响肘关节,使得上臂的运动带动前臂的运动;反过来,不管前臂如何运动都不会影响上臂。这就与现实中的情况相符合了。
现在,你已经对这种由多个小模型组成的复杂模型的运动规律有了一些了解,下面来看一下示例程序。
单关节模型
先来看一个单关节模型的例子。示例程序JointModel绘制了一个仅由两个立方体部件组成的机器人手臂,其运行结果如下图(左)所示;手臂的两个部件为arm1与arm2,arm1接在arm2的上面,如下图(右)所示。你可以把arm1想象成上臂,而把arm2想象成前臂,而肩关节在最下面(上臂在下而前臂在上,是为了以后加入手掌和手指后看得更清楚)。
JointModel程序中模型的层次结构
运行程序,用户可以使用左右方向键控制arm1(同时带动整条手臂)水平转动,使用上下方向键控制arm2绕joint1关节垂直转动。比如,先按下方向键,arm2逐渐向前倾斜(下图左),然后按右方向键,arm1向右旋转(下图右)。
如你所见,arm2绕joint1的转动并不影响arm1,而arm1的转动会带动arm2一起转动。
示例程序(JointMode.js)
如下显示了JointMode.js的代码,所有用来绘制和控制机器人手臂的逻辑都在JavaScript代码中。
var VSHADER_SOURCE = // p316'attribute vec4 a_Position;\n' +'attribute vec4 a_Normal;\n' +'uniform mat4 u_MvpMatrix;\n' + // 模型视图投影矩阵'uniform mat4 u_NormalMatrix;\n' + // 用于改变法向量的矩阵'uniform vec3 u_LightColor;\n' + // 平行光颜色'uniform vec3 u_AmbientColor;\n' + // 环境光颜色'varying vec4 v_Color;\n' +'void main() {\n' +' gl_Position = u_MvpMatrix * a_Position;\n' +// 光照计算,使场景更加逼真' vec3 lightDirection = normalize(vec3(0.0, 0.5, 0.7));\n' + // 归一化光线方向' vec4 color = vec4(1.0, 0.4, 0.0, 1.0);\n' + // 物体颜色' vec3 normal = normalize((u_NormalMatrix * a_Normal).xyz);\n' + // 归一化法向量' float nDotL = max(dot(normal, lightDirection), 0.0);\n' + // 点积 cos' vec3 ambient = u_AmbientColor * color.rgb;\n' + // 环境反射光颜色' vec3 diffuse = u_LightColor * color.rgb * nDotL;\n' + // 漫反射光颜色' v_Color = vec4(diffuse + ambient, color.a);\n' + // 最终颜色'}\n';var FSHADER_SOURCE ='#ifdef GL_ES\n' +'precision mediump float;\n' +'#endif\n' +'varying vec4 v_Color;\n' +'void main() {\n' +' gl_FragColor = v_Color;\n' +'}\n';function main() {var canvas = document.getElementById('webgl');var gl = getWebGLContext(canvas);if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) returnvar n = initVertexBuffers(gl);gl.clearColor(0.0, 0.0, 0.0, 1.0);gl.enable(gl.DEPTH_TEST);var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');var u_AmbientColor = gl.getUniformLocation(gl.program, 'u_AmbientColor');gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);gl.uniform3f(u_AmbientColor, 0.0, 1.0, 1.0);// 计算视图投影矩阵var viewProjMatrix = new Matrix4();viewProjMatrix.setPerspective(50.0, canvas.width / canvas.height, 1.0, 100.0);viewProjMatrix.lookAt(20.0, 10.0, 30.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);// 注册键盘事件响应函数document.onkeydown = function(ev){ keydown(ev, gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix); };draw(gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix); // 绘制立方体
}var ANGLE_STEP = 3.0; // 每次按键转动的角度
var g_arm1Angle = 0.0; // arml的当前角度
var g_joint1Angle = 0.0; // joint1的当前角度(即arm2的角度)
function keydown(ev, gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix) {switch (ev.keyCode) {case 38: // 上方向键 -> joint1绕z轴正向转动if (g_joint1Angle < 135.0) g_joint1Angle += ANGLE_STEP;break;case 40: // 下方向键 -> joint1绕z轴负向转动if (g_joint1Angle > -135.0) g_joint1Angle -= ANGLE_STEP;break;case 39: // 右方向键 -> arm1绕Y轴正方向转动g_arm1Angle = (g_arm1Angle + ANGLE_STEP) % 360;break;case 37: // 左方向键 -> arm1绕Y轴负方向转动g_arm1Angle = (g_arm1Angle - ANGLE_STEP) % 360;break;default: return;}// 绘制手臂draw(gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix);
}
function initVertexBuffers(gl) {// 顶点坐标(长方体宽度3.0,高度10.0,长度3.0,原点位于底部中心)var vertices = new Float32Array([1.5, 10.0, 1.5, -1.5, 10.0, 1.5, -1.5, 0.0, 1.5, 1.5, 0.0, 1.5, // v0-v1-v2-v3 front1.5, 10.0, 1.5, 1.5, 0.0, 1.5, 1.5, 0.0,-1.5, 1.5, 10.0,-1.5, // v0-v3-v4-v5 right1.5, 10.0, 1.5, 1.5, 10.0,-1.5, -1.5, 10.0,-1.5, -1.5, 10.0, 1.5, // v0-v5-v6-v1 up-1.5, 10.0, 1.5, -1.5, 10.0,-1.5, -1.5, 0.0,-1.5, -1.5, 0.0, 1.5, // v1-v6-v7-v2 left-1.5, 0.0,-1.5, 1.5, 0.0,-1.5, 1.5, 0.0, 1.5, -1.5, 0.0, 1.5, // v7-v4-v3-v2 down1.5, 0.0,-1.5, -1.5, 0.0,-1.5, -1.5, 10.0,-1.5, 1.5, 10.0,-1.5 // v4-v7-v6-v5 back]);// 法向量var normals = new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, // v7-v4-v3-v2 down0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0 // v4-v7-v6-v5 back]);// 顶点的索引var indices = new Uint8Array([0, 1, 2, 0, 2, 3, // front4, 5, 6, 4, 6, 7, // right8, 9,10, 8,10,11, // up12,13,14, 12,14,15, // left16,17,18, 16,18,19, // down20,21,22, 20,22,23 // back]);// 将顶点属性写入缓冲区(坐标和法线)if (!initArrayBuffer(gl, 'a_Position', vertices, gl.FLOAT, 3)) return -1;if (!initArrayBuffer(gl, 'a_Normal', normals, gl.FLOAT, 3)) return -1;gl.bindBuffer(gl.ARRAY_BUFFER, null);var indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);return indices.length;
}function initArrayBuffer(gl, attribute, data, type, num) {var buffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, buffer);gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);var a_attribute = gl.getAttribLocation(gl.program, attribute);gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);gl.enableVertexAttribArray(a_attribute);return true;
}// 坐标变换矩阵
var g_modelMatrix = new Matrix4(), g_mvpMatrix = new Matrix4();function draw(gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix) {gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);// Arm1var arm1Length = 10.0; // Length of arm1g_modelMatrix.setTranslate(0.0, -12.0, 0.0);g_modelMatrix.rotate(g_arm1Angle, 0.0, 1.0, 0.0); // 绕y轴旋转drawBox(gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix); // 绘制// Arm2g_modelMatrix.translate(0.0, arm1Length, 0.0); // 移动至joint1处g_modelMatrix.rotate(g_joint1Angle, 0.0, 0.0, 1.0); // 绕z轴旋转g_modelMatrix.scale(1.3, 1.0, 1.3); // 使立方体粗一点drawBox(gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix); // 绘制
}var g_normalMatrix = new Matrix4(); // 法线的旋转矩阵// 绘制立方体
function drawBox(gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix) {// 计算模型视图投影矩阵并传给u_MvpMatrix变量g_mvpMatrix.set(viewProjMatrix);g_mvpMatrix.multiply(g_modelMatrix); // 模型 视图投影 相乘得到最终矩阵gl.uniformMatrix4fv(u_MvpMatrix, false, g_mvpMatrix.elements);// 计算法线变换矩阵并传给u_NormalMatrix变量g_normalMatrix.setInverseOf(g_modelMatrix);g_normalMatrix.transpose();gl.uniformMatrix4fv(u_NormalMatrix, false, g_normalMatrix.elements);// 最终绘制gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}
代码详解
主要的变化发生在initVertexBuffers()函数,它将arm1和arm2的数据写入了相应的缓冲区。以前程序中的立方体都是以原点为中心,且边长为2.0;本例为了更好地模拟机器人手臂,使用如下图所示的立方体,原点位于底面中心,底面是边长为3.0的正方形,高度为10.0。将原点置于立方体的底面中心,是为了便于使立方体绕关节转动(比如,肘关节就位于前臂立方体的底面中心),如上图所示。arm1和arm2都使用这个立方体。
用来绘制机器人前臂和上臂的立方体
main()函数首先根据可视空间,视点和视线方向计算出了视图投影矩阵viewProjMatrix(第44~46行)。
然后在键盘事件响应函数中调用keydown()函数(第48行),通过方向键控制机器人的手臂运动。
接着定义keydown()函数本身(第55行),以及若干该函数需要用到的全局变量(第52、53和54行)。
ANGLE_STEP常量(第52行)表示每一次按下按键,arm1或joint1转动的角度,它的值是3.0。g_arm1Angle变量(第53行)表示arm1的当前角度,g_joint1Angle变量表示joint1的(也就是arm2的)当前角度,如下图所示。
g_joint1Angle和g_arm1Angle
keydown()函数(第55行)的任务是,根据按下的是哪个按键,对g_joint1Angle或g_arm1Angle变量加上或减去常量ANGLE_STEP的值。注意,joint1的转动角度只能在-135度到135度之间,这是为了不与arm1冲突。最后,draw()函数将整个机器人手臂绘制出来。
绘制层次模型(draw())
draw()函数的任务是绘制机器人手臂(第128行)。注意,draw()函数和drawBox()函数用到了全局变量g_modelMatrix和g_mvpMatrix(第126行)。
如你所见,draw()函数内部调用了drawBox()函数,每调用一次绘制一个部件,先绘制下方较细arm1,再绘制上方较粗arm2。
绘制单个部件的步骤是:(1)调用setTranslate()或translate()进行平移;(2)调用rotate()进行旋转;(3)调用drawBox()进行绘制。
绘制整个模型时,需要按照各部件的层次顺序,先arm1后arm2,再执行(1)平移,(2)旋转,(3)绘制。
绘制arm1的步骤如下:首先在模型矩阵g_modelMatrix上调用setTranslate()函数,使之平移(0.0,-12.0,0.0)到稍下方位置(第133行);然后调用rotate()函数,绕y轴旋转g_arm1Angle角度(第134行);最后调用drawBox()函数绘制arm1。
接着来绘制arm2,它与arm1在joint1处连接,如图g_joint1Angle和g_arm1Angle所示,我们应当从该处上开始绘制arm2。但是此时,模型矩阵还是处于绘制arm1的状态(向下平移并绕y轴旋转)下,所以得先调用translate()函数沿y轴向上平移arm1的高度arm1Length(第138行)。注意这里调用的是translate()而不是setTranslate(),因为这次平移是在之前的基础上进行的。
然后,使用g_joint1Angle进行肘关节处的转动(第139行),并在x和z轴稍作拉伸(第140行),使前臂看上去粗一些,以便与上臂区分开。
这样一来,每当keydown()函数更新了g_joint1Angle变量和g_arm1Angle变量的值,然后调用draw()函数进行绘制时,就能绘制出最新状态的机器人手臂,arm1的位置取决于g_arm1Angle变量,而arm2的位置取决于g_jointAngle变量(当然也受g_arm1Angle的影响)。
drawBox()函数的任务是绘制机器人手臂的某一个立方体部件,如上臂或前臂。它首先计算模型视图投影矩阵,传递给u_MvpMatrix变量(第149~151行),然后根据模型矩阵计算法向量变换矩阵,传递给u_NormalMatrix变量(第153~155行),最后绘制立方体(第157行)。
程序效果
相关文章:
WebGL层次模型——单节点模型
目录 多个简单模型组成的复杂模型 层次结构模型 单关节模型 JointModel程序中模型的层次结构 示例程序(JointMode.js) 代码详解 绘制层次模型(draw()) 程序效果 多个简单模型组成的复杂模型 绘制…...
【链表】反转链表 II-力扣 92 题
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…...
【考研数学】高等数学第六模块 —— 空间解析几何(1,向量基本概念与运算)
文章目录 引言一、空间解析几何的理论1.1 基本概念1.2 向量的运算 写在最后 引言 我自认空间想象能力较差,所以当初学这个很吃力。希望现在再接触,能好点。 一、空间解析几何的理论 1.1 基本概念 1.向量 —— 既有大小,又有方向的量称为向…...
巨人互动|Facebook海外户Facebook客户反馈分数
Facebook客户反馈分数是一项用于衡量用户对Facebook产品和服务满意度的指标。该指标被广泛应用于各种调研和评估活动,帮助Facebook了解用户对其平台和功能的意见和建议,并从中识别出改进的机会。 巨人互动|Facebook海外户&Facebook新闻提要的算法&am…...
Tomcat多实例部署和动静分离
一、多实例部署: 多实例:多实例就是在一台服务器上同时开启多个不同的服务端口,同时运行多个服务进程,这些服务进程通过不同的socket监听不同的服务端口来提供服务。 1.前期准备: 1.关闭防火墙:systemctl …...
关于 C/C++ 中在指针前加 const 关键字的作用说明
1. 作用说明: 在指针前加 const 的用途为:不可改变指针指向的内存的值,即将该指向指向的内存中的变量置为只读(read-only) 变量。 但是,可以给 const 的指针赋值,即将具有 const 属性的指针指向别的内存地…...
Vue.js新手指南:从零开始建立你的第一个应用
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
【案例】--EasyExcel导入导出文件案例
目录 一、前言二、EasyExcel解析(导入)文件2.1、EasyExcel选型2.2、如何存储excel解析的文件2.3、解析格式规则的excel文件2.4、解析未知格式规则的excel文件三、EasyExcel解析(导出)文件3.1、导出基本代码实现一、前言 最近项目中,需要对excel、csv等文件进行解析,并做相关…...
深入探索图像处理:从基础到高级应用
💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 图像处理是计算机视觉领…...
Jetpack Compose基础组件 - Image
Image的源码参数预览 Composable fun Image(painter: Painter,contentDescription: String?,modifier: Modifier Modifier,alignment: Alignment Alignment.Center,contentScale: ContentScale ContentScale.Fit,alpha: Float DefaultAlpha,colorFilter: ColorFilter? …...
UINavigationController内的页面跳转实现 UIViewController 的 present和dismiss动画
UINavigationController内部页面跳转默认为左右切换,但是当我们想向上弹出进入界面,或者向下离开界面时,需要实现UINavigationControllerDelegate 协议自行控制页面的动画(否则直接在navVc上叠加动画会导致动画结束后的那个页面,自…...
PMP对项目管理工作有什么用?
首先,项目管理岗位基本是不限行业的,所以,只要是项目管理相关的岗位,pmp证书都是能起到效果的,不用担心局限性太大,而且,pmp证书是国际证书,无论国企还是外企,都是认可这…...
Python 将‘20230919182550‘ 转换为 ‘%Y年%m月%d日 %H:%M‘
为了将给定的时间字符串 cur_time 转换为指定的格式,可以使用 Python 的 datetime 模块。以下是完成此操作的步骤: 使用 strptime 方法将 cur_time 转换为一个 datetime 对象。使用 strftime 方法将这个 datetime 对象转换为所需的格式。 这是具体的代…...
vue2.0检测无用的代码并删除
(1)、使用 useless-files-webpack-plugin 来查找无用文件 npm i useless-files-webpack-plugin -S (2)、vue.config.js中配置 const UselessFile require(useless-files-webpack-plugin)chainWebpack: config > {config.plu…...
小米华为,化干戈为玉帛!
近日来,手机圈又掀起了各大厂家推出新品的高潮。首先是华为Mate60的推出,其自研的麒麟9000S芯片瞬间点燃了国内手机市场,得到了国内甚至国外业界人士的认可和好评。 而近日网上盛传的小米创始人雷军的“愿意加入华为技术生态圈”的邀请&…...
【文末赠书】SRE求职必会 —— 可观测性平台可观测性工程(Observability Engineering)
文章目录 〇、导读一、实现可观测性平台的技术要点是什么?二、兼容全域信号量三、所谓全域信号量有哪些?四、统一采集和上传工具五、统一的存储后台六、自由探索和综合使用数据七、总结★推荐阅读《可观测性工程》直播预告直播主题直播时间预约直播 视频…...
content生成自定义图标的方式是什么?
animate.css是一个跨浏览器的CSS3动画库,它内置了很多经典的CSS3动画。使用起来很方便。下面我们通过例子讲解如何使用自定义类名和animate.css库实现动画效果。 (1)从animate.css官方网站获取animate.css文件,保存到chapter04目录中。 (2)创建C:\vue\…...
无涯教程-JavaScript - SECH函数
描述 SECH函数返回某个Angular的双曲正割。双曲正割是双曲余弦的倒数。因此,双曲正割的值由等式给出- $$\sinh\left(x\right)\frac {1} {\cosh\left(x\right)} \frac {2} {e ^ x e ^ {-x}} $$ 语法 SECH (number)争论 Argument描述Required/OptionalNumberNumber is the …...
天宇微纳芯片ic测试软件如何测试芯片上下电功能?
芯片的上电与下电功能测试是集成电路生产和研发过程中的关键环节,可以帮助企业确保产品的可靠性、整合性和兼容性,同时提高生产效率和产品质量。 因此在芯片的研发设计中,企业会对芯片的上下电有严格的要求,包括上下电的时序&…...
1万多爱背句子英语口语ACCESS\EXCEL数据库
今天这个数据库包含3个表,一个是分类表,一个是分类章节有,一个是具体句子表,表与表之间可以根据相关ID进行关联,是一个学习英语的好数据,具体请查收截图或样本: 数据有ACCESS数据库文件…...
C++:new 和 delete
个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》 文章目录 前言一、C内存管理1.内置类型2.自定义类型3.delete 与 new不匹配使用问题(VS平台下) 二、operator new 与 operator delete函数三、 new 和delete的实现原理内置类型自定义类型 四…...
mysql5.7版本的数据导入到mysql8.0版本需要怎么做
将 MySQL 5.7 版本的数据导入到 MySQL 8.0 版本,由于版本之间可能存在一些差异,需要采取一些步骤来确保数据导入的顺利进行。以下是一般的导入步骤: 备份数据: 在进行任何操作之前,务必备份 MySQL 5.7 数据库。可以使用…...
Python150题day06
1.4字典练习题 ①字典基本操作 dic { python: 95, java: 99, c: 100 } 用程序解答以下题目 1.字典的长度是多少 2.请修改java这个key对应的value值为98 3.删除 c 这个key 4.增加一个key-value对,key值为 php,value是90 5.获取所有的key值,存储在列表里…...
2023Node.js零基础教程(小白友好型),nodejs新手到高手,(一)NodeJS入门
写在开始前 在无尽的代码汪洪中,闪耀着一抹绚丽的光芒。它叫做Web前端开发! HTML是我们的魔法笔,是创造力的源泉。它将我们的思绪化为标签,将我们的想象变为元素。 在无尽的标签组合中,我们创造出独特的网页ÿ…...
拉格朗日乘子法思路来源
核心思路:由果索因 一. 直观理解 1. 问题描述 对于如"图1"式(等式约束优化问题, 可行域是边界), 转化成拉格朗日乘子法的思路来源: 图1: 拉格朗日乘子法问题描述图 如"图2",f为曲面.c为平面, 黑色加粗线是f和c的交线.(约束就是限制自变量的变化范围). …...
天选之子C++是如何发展起来的?如何学习C++呢?
天选之子C是如何发展起来的?如何学习C呢? 一、什么是C二、C发展史三、C的重要性3.1 语言的使用广泛度3.2 在工作领域 四、如何学习C4.1 大佬怎么学?4.2 自己怎么学 一、什么是C C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复…...
Oracle Schema Only账户
概念 Schema Only Accounts是Oracle 18c的新安全功能,19c进一步增强。 19c的增强其实就是允许此账户有管理权限:Ability to Grant or Revoke Administrative Privileges to and from Schema-Only Accounts A schema only account cannot log in to the…...
分界线-积木游戏 demo
目录 匿名信 题目描述: 输入描述 输出描述: 示例: Java实现 (期待看官能够修复一下, 害): 二、积木游戏 题目描述: 输入描述 输出描述 补充说明 示例 Java代码实现 匿名信 题目描述: 电视剧《分界线》里面有一个片段,男主为了向警察透露案件细节&…...
智能指针解读(2)
前面一篇文章,我讲解了智能指针的原理,并实现了一个简单的智能指针。为了加深对智能指针的理解,在这篇文章中,我把C中的几个智能指针讲解下:auto_ptr, unique_ptr, shared_ptr, weak_ptr。 1、auto_ptr 前面的文章我…...
javax.servlet.ServletException: 非法访问资源(/j_spring_security_check)
部署的web页面登录访问报错500状态码。 开发出于安全考虑引入了refer白名单,但是没有通知交付人员。 需要将浏览器访问的url加入到refer白名单中,问题解决。 filterconfig.xml <refer-domain> <value>http://localhost</value> …...
出名的wordpress模板/教你如何快速建站
compile 编译 / 测试 / 运行都会引入该 jar, 是 scope 的默认值 provided 编译 / 测试会引入该 jar, 运行时, 认为环境会自带这个 jarruntime 只在运行时, 引入该 jartest 在执行测试类时, 引入该 jarsystem 不去本地仓库搜索该 jar, 一般会搭配 systemPath 引用本地绝对路径上…...
做网站要不要营业执照/最近军事新闻热点大事件
郑重声明:本文纯属Fans同学的个人见解,仅供参考,欢迎拍砖。 软林至尊,Fans同盟。号令天下,莫敢不从。 Fans 1.老师教--这里的老师指大学教师。 优点:现场讲课,不懂可以问。 缺点:理…...
公司网站制作策划/seo赚钱培训
访问修饰符 修饰符 返回值类型 方法名(参数列表){ 语句块;} 访问修饰符:所有类成员访问修饰符都可以使用,如果省略访问修饰符,默认是private。 修饰符:在定义方法时修饰符包括virtual(虚拟的)、abstract(抽象的)、override(重…...
河北怀来县建设局网站/创量广告投放平台
1283: 序列 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 486 Solved: 280[Submit][Status][Discuss]Description 给出一个长度为 的正整数序列Ci,求一个子序列,使得原序列中任意长度为M的子串中被选出的元素不超过K(K,M<100) 个,并…...
专做国际时事评论网站/视频专用客户端app
Connection is not associated with a managed connection...
河南网站建设详细流程/株洲疫情最新情况
1、使用edu邮箱进行注册; 2、AD软件的安装;...