new Ammo.btSoftBodyHelpers() 是 Ammo.js 中的一个构造函数,用于创建软体物体的辅助对象,提供了一些方法来创建软体物体

news2024/11/24 13:55:27

demo案例
在这里插入图片描述

new Ammo.btSoftBodyHelpers() 是 Ammo.js 中的一个构造函数,用于创建软体物体的辅助对象,提供了一些方法来创建软体物体。以下是它的一些重要信息:

  • 入参:通常不需要传入参数。

  • 出参:创建的新的软体辅助对象。

  • 属性:该构造函数返回的对象通常没有额外的属性,它主要用于提供方法来创建软体物体。

  • 方法

    • CreateFromTriMesh(worldInfo, vertices, indices, numIndices, randomizeConstraints):基于三角网格创建软体物体。它接受以下参数:
      • worldInfo:物理世界信息对象。
      • vertices:顶点数组。
      • indices:索引数组。
      • numIndices:索引数量。
      • randomizeConstraints:是否随机化约束。
    • 其他用于创建软体物体的方法。

new Ammo.btTransform 是 Ammo.js 中的一个构造函数,用于创建表示刚体变换的对象。以下是它的一些重要信息:

  • 入参:通常不需要传入参数。如果需要初始化变换矩阵,可以传入一个矩阵对象。

  • 出参:创建的新的变换对象。

  • 属性

    • origin:表示变换的位置的向量。
    • rotation:表示变换的旋转的四元数。
  • 方法

    • setIdentity():将变换设置为单位变换。
    • setOrigin(origin):设置变换的位置。
    • setRotation(rotation):设置变换的旋转。
    • 其他用于获取和设置变换的位置和旋转的方法。

Ammo.js 物理软体体积的核心代码是在 createSoftVolume 函数中。具体来说,以下是该函数的关键部分:

function createSoftVolume( bufferGeom, mass, pressure ) {

    processGeometry( bufferGeom );

    const volume = new THREE.Mesh( bufferGeom, new THREE.MeshPhongMaterial( { color: 0xFFFFFF } ) );
    volume.castShadow = true;
    volume.receiveShadow = true;
    volume.frustumCulled = false;
    scene.add( volume );

    // 创建软体体积物理对象
    const volumeSoftBody = softBodyHelpers.CreateFromTriMesh(
        physicsWorld.getWorldInfo(),
        bufferGeom.ammoVertices,
        bufferGeom.ammoIndices,
        bufferGeom.ammoIndices.length / 3,
        true );

    const sbConfig = volumeSoftBody.get_m_cfg();
    sbConfig.set_viterations( 40 );
    sbConfig.set_piterations( 40 );

    // 设置软体的碰撞参数
    sbConfig.set_collisions( 0x11 );

    // 设置摩擦、阻尼和压力
    sbConfig.set_kDF( 0.1 );
    sbConfig.set_kDP( 0.01 );
    sbConfig.set_kPR( pressure );

    // 设置软体的刚度
    volumeSoftBody.get_m_materials().at( 0 ).set_m_kLST( 0.9 );
    volumeSoftBody.get_m_materials().at( 0 ).set_m_kAST( 0.9 );

    volumeSoftBody.setTotalMass( mass, false );
    Ammo.castObject( volumeSoftBody, Ammo.btCollisionObject ).getCollisionShape().setMargin( margin );
    physicsWorld.addSoftBody( volumeSoftBody, 1, - 1 );
    volume.userData.physicsBody = volumeSoftBody;
    // 禁用去激活
    volumeSoftBody.setActivationState( 4 );

    softBodies.push( volume );

}

这段代码首先调用 processGeometry 函数对几何体进行处理,然后创建一个 THREE.Mesh 对象表示软体体积的图形表示。接着,通过 softBodyHelpers.CreateFromTriMesh 方法创建了一个 Ammo.js 的软体体积物理对象,设置了软体的各种物理参数,最后将软体体积物理对象添加到物理世界中。

demo 源码

<html lang="en">
	<head>
		<title>Ammo.js软体体积演示</title> <!-- 设置页面标题 -->
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
		<style>
			body {
				color: #333;
			}
		</style>
	</head>
	<body>
		<div id="info">
			Ammo.js物理软体体积演示<br/> <!-- 页面顶部信息 -->
			点击以抛出一个球 <!-- 提示用户点击以抛出一个球 -->
		</div>
		<div id="container"></div>

		<script src="jsm/libs/ammo.wasm.js"></script> <!-- 引入Ammo.js库 -->

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js", <!-- 引入Three.js库 -->
					"three/addons/": "./jsm/"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three'; <!-- 导入Three.js库 -->

			import Stats from 'three/addons/libs/stats.module.js'; <!-- 导入性能统计库Stats.js -->

			import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; <!-- 导入OrbitControls控制器 -->
			import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; <!-- 导入BufferGeometryUtils工具库 -->

			// 图形变量
			let container, stats; <!-- 定义容器和性能统计变量 -->
			let camera, controls, scene, renderer; <!-- 定义相机、控制器、场景和渲染器变量 -->
			let textureLoader; <!-- 纹理加载器变量 -->
			const clock = new THREE.Clock(); <!-- 时钟变量 -->
			let clickRequest = false; <!-- 点击请求标志 -->
			const mouseCoords = new THREE.Vector2(); <!-- 鼠标坐标变量 -->
			const raycaster = new THREE.Raycaster(); <!-- 射线投射器变量 -->
			const ballMaterial = new THREE.MeshPhongMaterial( { color: 0x202020 } ); <!-- 球体材质 -->
			const pos = new THREE.Vector3(); <!-- 位置向量 -->
			const quat = new THREE.Quaternion(); <!-- 四元数变量 -->

			// 物理变量
			const gravityConstant = - 9.8; <!-- 重力常数 -->
			let physicsWorld; <!-- 物理世界变量 -->
			const rigidBodies = []; <!-- 刚体数组 -->
			const softBodies = []; <!-- 软体数组 -->
			const margin = 0.05; <!-- 边缘间距 -->
			let transformAux1; <!-- 辅助变换对象 -->
			let softBodyHelpers; <!-- 软体帮助对象 -->

			Ammo().then( function ( AmmoLib ) { <!-- 异步加载Ammo.js库 -->

				Ammo = AmmoLib;

				init(); <!-- 初始化 -->
				animate(); <!-- 动画循环 -->

			} );

			function init() { <!-- 初始化函数 -->

				initGraphics(); <!-- 初始化图形部分 -->

				initPhysics(); <!-- 初始化物理部分 -->

				createObjects(); <!-- 创建物体 -->

				initInput(); <!-- 初始化输入事件 -->

			}

			function initGraphics() { <!-- 初始化图形函数 -->

				container = document.getElementById( 'container' ); <!-- 获取容器元素 -->

				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.2, 2000 ); <!-- 创建透视相机 -->

				scene = new THREE.Scene(); <!-- 创建场景 -->
				scene.background = new THREE.Color( 0xbfd1e5 ); <!-- 设置场景背景色 -->

				camera.position.set( - 7, 5, 8 ); <!-- 设置相机位置 -->

				renderer = new THREE.WebGLRenderer( { antialias: true } ); <!-- 创建WebGL渲染器 -->
				renderer.setPixelRatio( window.devicePixelRatio ); <!-- 设置像素比 -->
				renderer.setSize( window.innerWidth, window.innerHeight ); <!-- 设置渲染器大小 -->
				renderer.shadowMap.enabled = true; <!-- 开启阴影映射 -->
				container.appendChild( renderer.domElement ); <!-- 将渲染器添加到容器中 -->

				controls = new OrbitControls( camera, renderer.domElement ); <!-- 创建轨道控制器 -->
				controls.target.set( 0, 2, 0 ); <!-- 设置控制器目标 -->
				controls.update(); <!-- 更新控制器状态 -->

				textureLoader = new THREE.TextureLoader(); <!-- 创建纹理加载器对象 -->

				const ambientLight = new THREE.AmbientLight( 0xbbbbbb ); <!-- 创建环境光 -->
				scene.add( ambientLight ); <!-- 将环境光添加到场景中 -->

				const light = new THREE.DirectionalLight( 0xffffff, 3 ); <!-- 创建方向光 -->
				light.position.set( - 10, 10, 5 ); <!-- 设置光源位置 -->
				light.castShadow = true; <!-- 开启阴影 -->
				const d = 20;
				light.shadow.camera.left = - d; <!-- 设置阴影相机左边界 -->
				light.shadow.camera.right = d; <!-- 设置阴影相机右边界 -->
				light.shadow.camera.top = d; <!-- 设置阴影相机上边界 -->
				light.shadow.camera.bottom = - d; <!-- 设置阴影相机下边界 -->

				light.shadow.camera.near = 2; <!-- 设置阴影相机近裁剪面 -->
				light.shadow.camera.far = 50; <!-- 设置阴影相机远裁剪面 -->

				light.shadow.mapSize.x = 1024; <!-- 设置阴影贴图大小 -->
				light.shadow.mapSize.y = 1024; <!-- 设置阴影贴图大小 -->

				scene.add( light ); <!-- 将光源添加到场景中 -->

				stats = new Stats(); <!-- 创建性能统计对象 -->
				stats.domElement.style.position = 'absolute'; <!-- 设置性能统计元素位置 -->
				stats.domElement.style.top = '0px'; <!-- 设置性能统计元素位置 -->
				container.appendChild( stats.domElement ); <!-- 将性能统计元素添加到容器中 -->


				window.addEventListener( 'resize', onWindowResize ); <!-- 监听窗口大小变化事件 -->

			}

			function initPhysics() { <!-- 初始化物理

函数 -->

				// 物理配置
				const collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration(); <!-- 创建碰撞配置对象 -->
				const dispatcher = new Ammo.btCollisionDispatcher( collisionConfiguration ); <!-- 创建碰撞分发器对象 -->
				const broadphase = new Ammo.btDbvtBroadphase(); <!-- 创建Broadphase对象 -->
				const solver = new Ammo.btSequentialImpulseConstraintSolver(); <!-- 创建约束求解器对象 -->
				const softBodySolver = new Ammo.btDefaultSoftBodySolver(); <!-- 创建软体求解器对象 -->
				physicsWorld = new Ammo.btSoftRigidDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration, softBodySolver ); <!-- 创建软硬体动力学世界对象 -->
				physicsWorld.setGravity( new Ammo.btVector3( 0, gravityConstant, 0 ) ); <!-- 设置重力 -->
				physicsWorld.getWorldInfo().set_m_gravity( new Ammo.btVector3( 0, gravityConstant, 0 ) ); <!-- 设置世界重力 -->

				transformAux1 = new Ammo.btTransform(); <!-- 创建辅助变换对象 -->
				softBodyHelpers = new Ammo.btSoftBodyHelpers(); <!-- 创建软体帮助对象 -->

			}

			function createObjects() { <!-- 创建物体函数 -->

				// 地面
				pos.set( 0, - 0.5, 0 );
				quat.set( 0, 0, 0, 1 );
				const ground = createParalellepiped( 40, 1, 40, 0, pos, quat, new THREE.MeshPhongMaterial( { color: 0xFFFFFF } ) ); <!-- 创建地面 -->
				ground.castShadow = true; <!-- 设置地面投射阴影 -->
				ground.receiveShadow = true; <!-- 设置地面接收阴影 -->
				textureLoader.load( 'textures/grid.png', function ( texture ) { <!-- 加载地面纹理 -->
					texture.colorSpace = THREE.SRGBColorSpace; <!-- 设置纹理色彩空间 -->
					texture.wrapS = THREE.RepeatWrapping; <!-- 设置纹理水平重复方式 -->
					texture.wrapT = THREE.RepeatWrapping; <!-- 设置纹理垂直重复方式 -->
					texture.repeat.set( 40, 40 ); <!-- 设置纹理重复次数 -->
					ground.material.map = texture; <!-- 设置地面材质纹理 -->
					ground.material.needsUpdate = true; <!-- 更新材质 -->
				} );

				// 创建软体体积
				const volumeMass = 15; <!-- 设置体积质量 -->

				const sphereGeometry = new THREE.SphereGeometry( 1.5, 40, 25 ); <!-- 创建球体几何体 -->
				sphereGeometry.translate( 5, 5, 0 ); <!-- 设置球体位置 -->
				createSoftVolume( sphereGeometry, volumeMass, 250 ); <!-- 创建球体软体体积 -->

				const boxGeometry = new THREE.BoxGeometry( 1, 1, 5, 4, 4, 20 ); <!-- 创建盒体几何体 -->
				boxGeometry.translate( - 2, 5, 0 ); <!-- 设置盒体位置 -->
				createSoftVolume( boxGeometry, volumeMass, 120 ); <!-- 创建盒体软体体积 -->

				// 斜坡
				pos.set( 3, 1, 0 );
				quat.setFromAxisAngle( new THREE.Vector3( 0, 0, 1 ), 30 * Math.PI / 180 );
				const obstacle = createParalellepiped( 10, 1, 4, 0, pos, quat, new THREE.MeshPhongMaterial( { color: 0x606060 } ) ); <!-- 创建斜坡 -->
				obstacle.castShadow = true; <!-- 设置斜坡投射阴影 -->
				obstacle.receiveShadow = true; <!-- 设置斜坡接收阴影 -->

			}

			function processGeometry( bufGeometry ) {

				// 只考虑位置值来合并顶点
				const posOnlyBufGeometry = new THREE.BufferGeometry();
				posOnlyBufGeometry.setAttribute( 'position', bufGeometry.getAttribute( 'position' ) );
				posOnlyBufGeometry.setIndex( bufGeometry.getIndex() );

				// 合并顶点以将三角形网格转换为索引三角形
				const indexedBufferGeom = BufferGeometryUtils.mergeVertices( posOnlyBufGeometry );

				// 创建索引数组,将索引顶点映射到bufGeometry顶点
				mapIndices( bufGeometry, indexedBufferGeom );

			}

			function isEqual( x1, y1, z1, x2, y2, z2 ) {

				const delta = 0.000001;
				return Math.abs( x2 - x1 ) < delta &&
						Math.abs( y2 - y1 ) < delta &&
						Math.abs( z2 - z1 ) < delta;

			}

			function mapIndices( bufGeometry, indexedBufferGeom ) {

				// 创建ammoVertices、ammoIndices和ammoIndexAssociation在bufGeometry中

				const vertices = bufGeometry.attributes.position.array;
				const idxVertices = indexedBufferGeom.attributes.position.array;
				const indices = indexedBufferGeom.index.array;

				const numIdxVertices = idxVertices.length / 3;
				const numVertices = vertices.length / 3;

				bufGeometry.ammoVertices = idxVertices;
				bufGeometry.ammoIndices = indices;
				bufGeometry.ammoIndexAssociation = [];

				for ( let i = 0; i < numIdxVertices; i ++ ) {

					const association = [];
					bufGeometry.ammoIndexAssociation.push( association );

					const i3 = i * 3;

					for ( let j = 0; j <

 numVertices; j ++ ) {

						const j3 = j * 3;
						if ( isEqual( idxVertices[ i3 ], idxVertices[ i3 + 1 ], idxVertices[ i3 + 2 ],
							vertices[ j3 ], vertices[ j3 + 1 ], vertices[ j3 + 2 ] ) ) {

							association.push( j3 );

						}

					}

				}

			}

			function createSoftVolume( bufferGeom, mass, pressure ) {

				processGeometry( bufferGeom );

				const volume = new THREE.Mesh( bufferGeom, new THREE.MeshPhongMaterial( { color: 0xFFFFFF } ) );
				volume.castShadow = true;
				volume.receiveShadow = true;
				volume.frustumCulled = false;
				scene.add( volume );

				textureLoader.load( 'textures/colors.png', function ( texture ) {

					volume.material.map = texture;
					volume.material.needsUpdate = true;

				} );

				// 体积物理对象
				const volumeSoftBody = softBodyHelpers.CreateFromTriMesh(
					physicsWorld.getWorldInfo(),
					bufferGeom.ammoVertices,
					bufferGeom.ammoIndices,
					bufferGeom.ammoIndices.length / 3,
					true );

				const sbConfig = volumeSoftBody.get_m_cfg();
				sbConfig.set_viterations( 40 );
				sbConfig.set_piterations( 40 );

				// 软-软体和软-刚体碰撞
				sbConfig.set_collisions( 0x11 );

				// 摩擦
				sbConfig.set_kDF( 0.1 );
				// 阻尼
				sbConfig.set_kDP( 0.01 );
				// 压力
				sbConfig.set_kPR( pressure );
				// 刚度
				volumeSoftBody.get_m_materials().at( 0 ).set_m_kLST( 0.9 );
				volumeSoftBody.get_m_materials().at( 0 ).set_m_kAST( 0.9 );

				volumeSoftBody.setTotalMass( mass, false );
				Ammo.castObject( volumeSoftBody, Ammo.btCollisionObject ).getCollisionShape().setMargin( margin );
				physicsWorld.addSoftBody( volumeSoftBody, 1, - 1 );
				volume.userData.physicsBody = volumeSoftBody;
				// 禁用去激活
				volumeSoftBody.setActivationState( 4 );

				softBodies.push( volume );

			}

			function createParalellepiped( sx, sy, sz, mass, pos, quat, material ) {

				const threeObject = new THREE.Mesh( new THREE.BoxGeometry( sx, sy, sz, 1, 1, 1 ), material );
				const shape = new Ammo.btBoxShape( new Ammo.btVector3( sx * 0.5, sy * 0.5, sz * 0.5 ) );
				shape.setMargin( margin );

				createRigidBody( threeObject, shape, mass, pos, quat );

				return threeObject;

			}

			function createRigidBody( threeObject, physicsShape, mass, pos, quat ) {

				threeObject.position.copy( pos );
				threeObject.quaternion.copy( quat );

				const transform = new Ammo.btTransform();
				transform.setIdentity();
				transform.setOrigin( new Ammo.btVector3( pos.x, pos.y, pos.z ) );
				transform.setRotation( new Ammo.btQuaternion( quat.x, quat.y, quat.z, quat.w ) );
				const motionState = new Ammo.btDefaultMotionState( transform );

				const localInertia = new Ammo.btVector3( 0, 0, 0 );
				physicsShape.calculateLocalInertia( mass, localInertia );

				const rbInfo = new Ammo.btRigidBodyConstructionInfo( mass, motionState, physicsShape, localInertia );
				const body = new Ammo.btRigidBody( rbInfo );

				threeObject.userData.physicsBody = body;

				scene.add( threeObject );

				if ( mass > 0 ) {

					rigidBodies.push( threeObject );

					// 禁用去激活
					body.setActivationState( 4 );

				}

				physicsWorld.addRigidBody( body );

				return body;

			}

			function initInput() {

				window.addEventListener( 'pointerdown', function ( event ) {

					if ( ! clickRequest ) {

						mouseCoords.set(
							( event.clientX / window.innerWidth ) * 2 - 1,
							- ( event.clientY / window.innerHeight ) * 2 + 1
						);

						clickRequest = true;

					}

				} );

			}

			function processClick() {

				if ( clickRequest ) {

					raycaster.setFromCamera( mouseCoords, camera );

					// 创建球体
					const ballMass = 3;
					const ballRadius = 0.4;

					const ball = new THREE.Mesh( new THREE.SphereGeometry( ballRadius, 18, 16 ), ballMaterial );
					ball.castShadow = true;
					ball.receiveShadow = true;
					const ballShape = new Ammo.btSphereShape( ballRadius );
					ballShape.setMargin( margin );
					pos.copy( raycaster.ray.direction );
					pos.add( raycaster.ray.origin );
					quat.set( 0, 0, 0, 1 );
					const ballBody = createRigidBody( ball, ballShape, ballMass, pos, quat );
					ballBody.setFriction( 0.5 );

					pos.copy( raycaster.ray.direction );
					pos.multiplyScalar( 14 );
					ballBody.setLinearVelocity( new Ammo.btVector3( pos.x, pos.y, pos.z ) );

					clickRequest = false;

				}

			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			function animate() {

				requestAnimationFrame( animate );

				render();
				stats.update();

			}

			function render() {

				const deltaTime = clock.getDelta();

				updatePhysics( deltaTime );

				processClick();

				renderer.render( scene, camera );

			}

			function updatePhysics( deltaTime ) {

				// 步进世界
				physicsWorld.stepSimulation( deltaTime, 10 );

				// 更新软体体积
				for ( let i = 0, il = softBodies.length; i < il; i ++ ) {

					const volume = softBodies[ i ];
					const geometry = volume.geometry;
					const softBody = volume.userData.physicsBody;
					const volumePositions = geometry.attributes.position.array;
					const volumeNormals = geometry.attributes.normal.array;
					const association = geometry.ammoIndexAssociation;
					const numVerts = association.length;
					const nodes = softBody.get_m_nodes();
					for ( let j = 0; j < numVerts; j ++ ) {

						const node = nodes.at( j );
						const nodePos = node.get_m_x();
						const x =

 nodePos.x();
						const y = nodePos.y();
						const z = nodePos.z();
						const nodeNormal = node.get_m_n();
						const normal = association[ j ];
						for ( let k = 0, kl = normal.length; k < kl; k ++ ) {

							const indexVertex = normal[ k ];
							volumePositions[ indexVertex ] = x;
							volumePositions[ indexVertex + 1 ] = y;
							volumePositions[ indexVertex + 2 ] = z;

							volumeNormals[ indexVertex ] = - nodeNormal.x();
							volumeNormals[ indexVertex + 1 ] = - nodeNormal.y();
							volumeNormals[ indexVertex + 2 ] = - nodeNormal.z();

						}

					}

					geometry.attributes.position.needsUpdate = true;
					geometry.attributes.normal.needsUpdate = true;

				}

				// 更新物体位置
				for ( let i = 0, il = rigidBodies.length; i < il; i ++ ) {

					const objThree = rigidBodies[ i ];
					const objPhys = objThree.userData.physicsBody;
					const ms = objPhys.getMotionState();
					if ( ms ) {

						ms.getWorldTransform( transformAux1 );
						const p = transformAux1.getOrigin();
						const q = transformAux1.getRotation();
						objThree.position.set( p.x(), p.y(), p.z() );
						objThree.quaternion.set( q.x(), q.y(), q.z(), q.w() );

					}

				}

			}

		</script>

	</body>
</html>

本内容来源于小豆包,想要更多内容请跳转小豆包 》

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

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

相关文章

软件设计师-基础知识科目-面向对象技术知识7

七、面向对象技术知识&#xff1a; 面向对象基础知识&#xff1a; 对象&#xff1a; 对象的组成部分包括&#xff1a;对象名&#xff0c;状态(属性)&#xff0c;行为(操作)。 类&#xff1a; 类的分类&#xff1a;实体类、接口类(边界类)和控制类。 实体类的对象&#xff…

CentOS7 boa服务器的搭建和配置

环境是CentOS7&#xff0c;但方法不局限于此版系统&#xff0c;应该是通用的。 具体步骤如下&#xff1a; 1. 下载boa源码 下载地址: Boa Webserver 下载后&#xff0c;进入压缩包所在目录&#xff0c;进行解压&#xff1a; tar xzf boa-0.94.13.tar.gz 2. 安装需要的工具b…

信息系统项目管理师——第23章组织通用管理

本章在第三版流程和知识管理的基础上新增了2节内容&#xff0c;从2023年上半年的考情来看来 选择题&#xff0c;考1分左右&#xff0c;知识点比较分散&#xff0c;刷下题&#xff0c;考前突击下即可。 案例题&#xff0c;不考。 论文题&#xff0c;不考。 1人力资源管理 1.人…

微服务学习(黑马)

学习黑马的微服务课程的笔记 导学 微服务架构 认识微服务 SpringCloud spring.io/projects/spring-cloud/ 服务拆分和远程调用 根据订单id查询订单功能 存在的问题 硬编码 eureka注册中心 搭建eureka 服务注册 在order-service中完成服务拉取 Ribbon负载均衡 Nacos注册中心…

结合ArcGIS+SWAT模型+Century模型:流域生态系统水-碳-氮耦合过程模拟

原文链接&#xff1a;结合ArcGISSWAT模型Century模型&#xff1a;流域生态系统水-碳-氮耦合过程模拟https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&tempkeyMTI2NV9sMGRZNUJoVkNVc1ZzSzRuMl9XXzhqX0R3cXpESWFwM1E4cFY4ejNqWFh3VUl0dlZkNWk4b20ydFdFTy1xS2ZObGN0Z0ZXSjly…

交流电源的频率如何测试

交流电源的频率是指每秒钟交流电源周期的数量&#xff0c;通常是50Hz和60Hz。但是在实际使用中会有一定的波动&#xff0c;一般交流电源频率的波动范围是10%。 交流电源频率的高低对电路有很大的影响&#xff0c;直接影响着电能质量和电路的稳定性。此外&#xff0c;交流电源的…

Docker核心特征

Docker的基本概念 Dockerfile&#xff1a;制作进行的文件&#xff0c;可以理解为制作镜像的一个清单。 镜像&#xff1a;用来创建容器的安装包&#xff0c;可以理解为给电脑安装操作系统的系统镜像。 容器&#xff1a;通过镜像来创建的一套运行环境&#xff0c;一个容器里可…

eBPF 主题分享:Kindling-OriginX 解密如何揭开可观测性盲区实现根因推导

“第二届eBPF开发者大会”将于2024年4月13日在陕西省西安市线下召开,由西安邮电大学主办。本次大会以“发挥eBPF技术力量&#xff0c;提升计算机系统可观测性和性能”为主题&#xff0c;涵盖了eBPF技术及发展、eBPF网络安全应用、eBPF可观测性及应用、软件性能工程等方面&#…

代理模式:控制对象访问的智能方式

在面向对象的软件开发中&#xff0c;代理模式是一种结构型设计模式&#xff0c;它为其他对象提供一个代理或占位符以控制对这个对象的访问。代理模式在实现权限控制、延迟初始化和远程对象访问等方面非常有用。本文将详细介绍代理模式的定义、实现、应用场景以及优缺点&#xf…

Tomcat以服务方式启动,无法访问网络共享目录问题

关于“Tomcat以服务方式启动&#xff0c;无法访问网络共享目录问题”解决方式如下&#xff1a; 1、通过doc命令【services.msc】打开本地服务找到&#xff0c;找到tomcat服务所在位置 2、右键打开Tomcat服务的属性 3、选择 登陆选项卡 4、选择“此账户”选项&#xff0c;并…

预告:(阶乘)+统计读取的单个字符+把我电脑给干关机了的题,还好在tmp里面找到(穷举法编程)+(双循环算法)+(最大公约数,最小公倍数)

在赶一篇作业出来 第一个&#xff1a; 题目&#xff1a;编程实现&#xff0c;求saaaaaaaa⋯an个a的值&#xff0c;其中a是一个数字。例如当a为2&#xff0c;n为5时&#xff0c;计算&#xff0c;2&#xff0b;22&#xff0b;222&#xff0b;2222&#xff0b;22222的值。 #inc…

elementUI 下拉框加提示文案

效果如下&#xff1a; 展示文案在最下面&#xff0c;跟选项有个分割线 <el-select v-model"value" placeholder"请选择" clearable popper-class"addNotice" class"addNoticeS" visible-change"(v) >selectNotice(v,展示…

物联网SaaS平台

在信息化、智能化浪潮席卷全球的今天&#xff0c;物联网SaaS平台作为推动工业数字化转型的重要工具&#xff0c;正日益受到广泛关注。那么&#xff0c;物联网SaaS平台究竟是什么&#xff1f;HiWoo Cloud作为物联网SaaS平台又有哪些独特优势&#xff1f;更重要的是&#xff0c;它…

Docker 学习笔记(三):Centos7 中 Docker 使用,镜像、容器,以及操作等常用命令小结

一、前言 记录时间 [2024-4-7] 前置文章&#xff1a; Docker学习笔记&#xff08;一&#xff09;&#xff1a;入门篇&#xff0c;Docker概述、基本组成等&#xff0c;对Docker有一个初步的认识 Docker学习笔记&#xff08;二&#xff09;&#xff1a;在Linux中部署Docker&#…

IDEA2023连接服务器docker并部署ruoyi-cloud-plus项目

文章目录 TCP 方式连接docker1. 服务器docker配置修改查看虚拟机中Docker配置文件位置修改配置文件重启docker服务关闭防火墙 2. idea安装docker插件3. idea连接docker服务 部署ruoyi-cloud-plus项目1. 项目环境说明2. 安装Centos73. 安装docker4. idea配置服务器SSH连接5. ide…

SHAP安装问题

一、安装 pip install shap -i https://pypi.tuna.tsinghua.edu.cn/simple 二、遇到问题 1、提示报错如下&#xff1a; ModuleNotFoundError: No module named numba.core 安装numba&#xff1a; pip install numba -i https://pypi.tuna.tsinghua.edu.cn/simple 提示已经…

【go从入门到精通】作用域,包详解

作者简介&#xff1a; 高科&#xff0c;先后在 IBM PlatformComputing从事网格计算&#xff0c;淘米网&#xff0c;网易从事游戏服务器开发&#xff0c;拥有丰富的C&#xff0c;go等语言开发经验&#xff0c;mysql&#xff0c;mongo&#xff0c;redis等数据库&#xff0c;设计模…

基于React封装Handsontable并兼容antd

背景 其实Handsontable官方也提供了React的版本&#xff0c;但是官方的版本再编辑和渲染的时候并不能够很好的嵌入第三方的组件库。这就导致了&#xff0c;使用了Handsontable就没有办和普通的react项目一样轻松引用其他第三方组件。因此对其react的版本进行了二次的封装&#…

MySQL之sql性能分析

sql执行频率 MySQL客户端连接成功后&#xff0c;通过show[session|global]status命令可以提供服务器状态信息。通过如下指令&#xff0c;可以查看当前数据库的所有INSERT、DELETE、UPDATE、SELECT的访问频次。 慢日志查询 慢查询日志记录了所有执行时间超过指定参数(longquer…

石子合并(区间dp)-java

石子合并问题是经典的区间dp问题&#xff0c;我们需要枚举中间端点k的情况从而来推出dp数组的值。 文章目录 前言 一、石子合并问题 二、算法思路 1.问题思路 2.状态递推公式 二、代码如下 代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入数据 3.代码运行结果如下&am…