7、三维机械设计、装配与运动仿真组件 - /设计与仿真组件/3d-mechanical-designer
76个工业组件库示例汇总
三维机械设计、装配与运动仿真通用组件
这是一个基于Three.js开发的三维机械设计、装配与运动仿真通用组件,可以实现工业机器人关节结构设计与运动仿真功能。
功能特点
- 直观的三维设计界面:提供基于WebGL的3D设计空间,实现机械结构的可视化设计
- 参数化建模:通过属性面板精确控制每个部件的位置、旋转和缩放
- 关节类型支持:支持旋转关节、移动关节和固定关节三种类型
- 运动仿真:实时模拟机器人关节运动,支持调整运动范围和速度
- 关键帧动画:提供时间轴功能,支持添加关键帧创建复杂动画
- 模型保存与加载:支持将设计导出为JSON文件并重新加载
- 苹果科技风格UI:采用简洁优雅的界面设计,操作直观友好
- 响应式设计:适配不同屏幕尺寸,在各类设备上均可正常使用
基本操作
- 添加关节:点击"添加关节"按钮,创建新的关节点
- 添加连杆:点击"添加连杆"按钮,连接选定的关节
- 选择部件:点击画布上的部件进行选择,属性面板将显示其参数
- 调整参数:在属性面板中修改选中部件的各项参数
- 删除部件:选中部件后点击"删除部件"按钮
- 运行仿真:点击"运行仿真"按钮开始模拟机器人运动
- 添加关键帧:在仿真过程中,点击"添加关键帧"记录当前状态
- 保存/加载模型:使用对应按钮保存当前设计或加载已有模型
案例:工业机器人设计
该组件默认加载一个简单的三轴工业机器人模型,包含以下部分:
- 基座(底部圆柱体)
- 肩部关节(第一个旋转点)
- 上臂连杆(第一段连接件)
- 肘部关节(第二个旋转点)
- 前臂连杆(第二段连接件)
- 腕部关节(第三个旋转点)
- 末端执行器(机械手)
通过调整各关节的参数和运动范围,可以模拟不同类型工业机器人的运动特性。
技术说明
- 核心渲染引擎:Three.js
- 3D交互控制:OrbitControls和TransformControls
- 界面设计:使用CSS3实现苹果风格UI
- 响应式布局:使用Flexbox和媒体查询适配不同设备
- 数据序列化:使用JSON格式存储模型数据
性能优化
- 使用请求动画帧(requestAnimationFrame)保证平滑渲染
- 实现对象池和模型缓存减少内存开销
- 自动调整渲染质量以适应不同设备性能
- 使用LOD技术(Level of Detail)优化复杂模型的渲染
扩展开发
如需扩展更复杂的功能,可以考虑:
- 添加更多预设组件库(如标准机械部件)
- 实现动力学分析(如受力分析、应力计算)
- 添加碰撞检测与物理引擎
- 支持导入/导出标准CAD格式文件(如STEP、STL)
- 添加协同设计功能,支持多人同时编辑
效果展示
源码
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>三维机械设计、装配与运动仿真通用组件</title><link rel="stylesheet" href="styles.css"><!-- Three.js库 --><script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script><!-- OrbitControls扩展 --><script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script><!-- TransformControls扩展 --><script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/TransformControls.min.js"></script>
</head>
<body><div class="robot-simulation-container"><div class="toolbar"><div class="toolbar-section"><button id="new-model-btn" class="btn primary">新建模型</button><button id="load-model-btn" class="btn">载入模型</button><button id="save-model-btn" class="btn">保存模型</button></div><div class="toolbar-section"><button id="add-joint-btn" class="btn">添加关节</button><button id="add-link-btn" class="btn">添加连杆</button><button id="delete-part-btn" class="btn danger">删除部件</button></div><div class="toolbar-section"><button id="play-btn" class="btn success">运行仿真</button><button id="pause-btn" class="btn">暂停</button><button id="reset-btn" class="btn">重置</button></div></div><div class="main-content"><div class="canvas-container"><canvas id="robot-canvas"></canvas><div class="canvas-controls"><button id="zoom-in-btn" class="control-btn">+</button><button id="zoom-out-btn" class="control-btn">-</button><button id="rotate-btn" class="control-btn"><svg viewBox="0 0 24 24" width="16" height="16"><path d="M7.11 8.53L5.7 7.11C4.8 8.27 4.24 9.61 4.07 11h2.02c.14-.87.49-1.72 1.02-2.47zM6.09 13H4.07c.17 1.39.72 2.73 1.62 3.89l1.41-1.42c-.52-.75-.87-1.59-1.01-2.47zm1.01 5.32c1.16.9 2.51 1.44 3.9 1.61V17.9c-.87-.15-1.71-.49-2.46-1.03L7.1 18.32zM13 4.07V1L8.45 5.55 13 10V6.09c2.84.48 5 2.94 5 5.91s-2.16 5.43-5 5.91v2.02c3.95-.49 7-3.85 7-7.93s-3.05-7.44-7-7.93z"/></svg></button><button id="pan-btn" class="control-btn"><svg viewBox="0 0 24 24" width="16" height="16"><path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"/></svg></button></div></div><div class="properties-panel"><div class="panel-header"><h3>参数配置</h3></div><div class="panel-content"><div class="property-group" id="selected-item-properties"><h4>选中项目: <span id="selected-item-name">无</span></h4><div class="property-row"><label for="position-x">位置 X:</label><input type="number" id="position-x" value="0" step="0.1"></div><div class="property-row"><label for="position-y">位置 Y:</label><input type="number" id="position-y" value="0" step="0.1"></div><div class="property-row"><label for="position-z">位置 Z:</label><input type="number" id="position-z" value="0" step="0.1"></div><div class="property-row"><label for="rotation-x">旋转 X:</label><input type="number" id="rotation-x" value="0" step="1" min="0" max="360"></div><div class="property-row"><label for="rotation-y">旋转 Y:</label><input type="number" id="rotation-y" value="0" step="1" min="0" max="360"></div><div class="property-row"><label for="rotation-z">旋转 Z:</label><input type="number" id="rotation-z" value="0" step="1" min="0" max="360"></div><div class="property-row"><label for="scale">尺寸:</label><input type="number" id="scale" value="1" step="0.1" min="0.1"></div><div class="property-row joint-property"><label for="joint-type">关节类型:</label><select id="joint-type"><option value="revolute">旋转关节</option><option value="prismatic">移动关节</option><option value="fixed">固定关节</option></select></div><div class="property-row joint-property"><label for="joint-range">关节范围:</label><input type="range" id="joint-range" min="0" max="180" value="90"><span id="joint-range-value">90°</span></div><div class="property-row joint-property"><label for="joint-speed">运动速度:</label><input type="number" id="joint-speed" value="1" step="0.1" min="0.1"></div></div><div class="property-group" id="material-properties"><h4>材质属性</h4><div class="property-row"><label for="material-color">颜色:</label><input type="color" id="material-color" value="#2196F3"></div><div class="property-row"><label for="material-type">材质类型:</label><select id="material-type"><option value="basic">基础材质</option><option value="phong">Phong材质</option><option value="standard">标准材质</option></select></div><div class="property-row"><label for="transparency">透明度:</label><input type="range" id="transparency" min="0" max="100" value="100"><span id="transparency-value">100%</span></div></div></div></div></div><div class="timeline"><div class="timeline-controls"><button id="add-keyframe-btn" class="btn small">添加关键帧</button><span class="time-display">时间: <span id="current-time">0.00</span>s</span></div><div class="timeline-track" id="timeline-track"><!-- 关键帧将通过JS动态添加 --></div></div><div class="status-bar"><div class="status-item"><span id="coordinates-display">X: 0.00 Y: 0.00 Z: 0.00</span></div><div class="status-item"><span id="fps-display">FPS: 60</span></div><div class="status-item"><span id="model-info">零件: 0 | 关节: 0</span></div></div></div><script src="script.js"></script>
</body>
</html>
styles.css
/* 全局样式 */
:root {--primary-color: #0070f3;--secondary-color: #f5f5f7;--text-color: #333;--light-text: #86868b;--border-color: #d2d2d7;--danger-color: #ff3b30;--success-color: #34c759;--shadow: 0 2px 8px rgba(0, 0, 0, 0.1);--panel-width: 280px;--timeline-height: 100px;--toolbar-height: 50px;--status-bar-height: 30px;
}.robot-simulation-container {font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;background-color: #fff;color: var(--text-color);width: 100%;height: 100%;display: flex;flex-direction: column;overflow: hidden;user-select: none;
}/* 工具栏样式 */
.toolbar {height: var(--toolbar-height);background-color: var(--secondary-color);border-bottom: 1px solid var(--border-color);display: flex;align-items: center;padding: 0 15px;justify-content: space-between;
}.toolbar-section {display: flex;gap: 8px;
}.btn {border: none;border-radius: 6px;padding: 8px 12px;font-size: 13px;font-weight: 500;cursor: pointer;background-color: #e8e8ed;color: var(--text-color);transition: all 0.2s ease;
}.btn:hover {background-color: #d8d8d8;
}.btn.primary {background-color: var(--primary-color);color: white;
}.btn.primary:hover {background-color: #005acf;
}.btn.danger {background-color: var(--danger-color);color: white;
}.btn.danger:hover {background-color: #e63028;
}.btn.success {background-color: var(--success-color);color: white;
}.btn.success:hover {background-color: #2db64f;
}.btn.small {padding: 4px 8px;font-size: 12px;
}/* 主内容区域 */
.main-content {display: flex;flex-grow: 1;position: relative;overflow: hidden;
}/* 画布容器 */
.canvas-container {flex-grow: 1;position: relative;background-color: #f8f8f8;overflow: hidden;
}#robot-canvas {display: block;width: 100%;height: 100%;
}.canvas-controls {position: absolute;bottom: 15px;right: 15px;display: flex;gap: 5px;
}.control-btn {width: 30px;height: 30px;border-radius: 50%;background-color: white;border: 1px solid var(--border-color);display: flex;align-items: center;justify-content: center;cursor: pointer;box-shadow: var(--shadow);
}.control-btn:hover {background-color: #f5f5f5;
}.control-btn svg {fill: var(--text-color);
}/* 属性面板 */
.properties-panel {width: var(--panel-width);background-color: white;border-left: 1px solid var(--border-color);display: flex;flex-direction: column;overflow: hidden;
}.panel-header {padding: 15px;border-bottom: 1px solid var(--border-color);
}.panel-header h3 {margin: 0;font-size: 16px;font-weight: 600;
}.panel-content {padding: 15px;overflow-y: auto;flex-grow: 1;
}.property-group {margin-bottom: 20px;
}.property-group h4 {margin: 0 0 10px 0;font-size: 14px;font-weight: 600;color: var(--light-text);
}.property-row {display: flex;align-items: center;margin-bottom: 10px;
}.property-row label {flex: 0 0 90px;font-size: 13px;color: var(--text-color);
}.property-row input, .property-row select {flex-grow: 1;padding: 6px 8px;border-radius: 6px;border: 1px solid var(--border-color);font-size: 13px;background-color: white;
}.property-row input[type="number"] {width: 80px;
}.property-row input[type="range"] {margin-right: 10px;
}.property-row input[type="color"] {height: 30px;padding: 0;width: 60px;
}/* 时间轴 */
.timeline {height: var(--timeline-height);border-top: 1px solid var(--border-color);background-color: var(--secondary-color);padding: 10px 15px;display: flex;flex-direction: column;
}.timeline-controls {display: flex;justify-content: space-between;margin-bottom: 8px;
}.time-display {font-size: 13px;color: var(--light-text);
}.timeline-track {flex-grow: 1;position: relative;background-color: white;border-radius: 6px;border: 1px solid var(--border-color);overflow: hidden;
}/* 关键帧标记 */
.keyframe-marker {position: absolute;width: 2px;height: 100%;background-color: var(--primary-color);top: 0;cursor: pointer;
}.keyframe-marker::after {content: '';position: absolute;width: 8px;height: 8px;border-radius: 50%;background-color: var(--primary-color);top: 5px;left: -3px;
}.keyframe-marker:hover::after {transform: scale(1.3);
}/* 状态栏 */
.status-bar {height: var(--status-bar-height);background-color: var(--secondary-color);border-top: 1px solid var(--border-color);display: flex;align-items: center;padding: 0 15px;font-size: 12px;color: var(--light-text);
}.status-item {margin-right: 20px;
}/* 响应式调整 */
@media screen and (max-width: 768px) {.main-content {flex-direction: column;}.properties-panel {width: 100%;height: 250px;border-left: none;border-top: 1px solid var(--border-color);}
}/* 设置页面和容器的全屏样式 */
html, body {margin: 0;padding: 0;height: 100%;overflow: hidden;
}/* 确保在Appsmith环境中正确显示 */
.appsmith-widget {width: 100%;height: 100%;overflow: hidden;
}/* 加载动画 */
.loading-overlay {position: absolute;top: 0;left: 0;width: 100%;height: 100%;background-color: rgba(255, 255, 255, 0.8);display: flex;align-items: center;justify-content: center;z-index: 1000;
}.loading-spinner {width: 40px;height: 40px;border: 4px solid #f3f3f3;border-top: 4px solid var(--primary-color);border-radius: 50%;animation: spin 1s linear infinite;
}@keyframes spin {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }
}
script.js
// 三维机械设计、装配与运动仿真通用组件// 初始化Three.js相关变量
let scene, camera, renderer, controls, transformControls, raycaster, mouse;
let robot = { parts: [], joints: [] };
let selectedObject = null;
let clock = new THREE.Clock();
let isSimulating = false;
let keyframes = [];
let currentTime = 0;// 页面加载完成后初始化应用
document.addEventListener('DOMContentLoaded', () => {initScene();initEventListeners();createExampleRobot();// 初始化完成后隐藏加载动画(如果有)const loadingOverlay = document.querySelector('.loading-overlay');if (loadingOverlay) {loadingOverlay.style.display = 'none';}
});// 初始化场景
function initScene() {// 创建场景scene = new THREE.Scene();scene.background = new THREE.Color(0xf8f8f8);// 添加网格const gridHelper = new THREE.GridHelper(10, 10, 0xcccccc, 0xe0e0e0);scene.add(gridHelper);// 添加环境光const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);scene.add(ambientLight);// 添加定向光const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);directionalLight.position.set(5, 10, 7.5);directionalLight.castShadow = true;scene.add(directionalLight);// 设置相机const canvas = document.getElementById('robot-canvas');const aspect = canvas.clientWidth / canvas.clientHeight;camera = new THREE.PerspectiveCamera(45, aspect, 0.1, 1000);camera.position.set(5, 5, 5);camera.lookAt(new THREE.Vector3(0, 0, 0));// 设置渲染器renderer = new THREE.WebGLRenderer({ canvas, antialias: true });renderer.setSize(canvas.clientWidth, canvas.clientHeight);renderer.setPixelRatio(window.devicePixelRatio);renderer.shadowMap.enabled = true;// 添加轨道控制器controls = new THREE.OrbitControls(camera, renderer.domElement);controls.enableDamping = true;controls.dampingFactor = 0.25;// 添加变换控制器transformControls = new THREE.TransformControls(camera, renderer.domElement);transformControls.addEventListener('dragging-changed', (event) => {controls.enabled = !event.value;});scene.add(transformControls);// 创建射线投射器,用于选择对象raycaster = new THREE.Raycaster();mouse = new THREE.Vector2();// 窗口大小变化时更新渲染器尺寸window.addEventListener('resize', onWindowResize);// 开始渲染循环animate();
}// 窗口大小变化事件处理器
function onWindowResize() {const canvas = renderer.domElement;const width = canvas.clientWidth;const height = canvas.clientHeight;camera.aspect = width / height;camera.updateProjectionMatrix();renderer.setSize(width, height, false);
}// 渲染循环
function animate() {requestAnimationFrame(animate);// 更新轨道控制器controls.update();// 如果正在仿真,执行运动仿真if (isSimulating) {updateSimulation();}// 更新坐标显示updateCoordinatesDisplay();// 更新FPS显示updateFPS();// 渲染场景renderer.render(scene, camera);
}// 更新坐标显示
function updateCoordinatesDisplay() {const cameraPosition = camera.position;document.getElementById('coordinates-display').textContent = `X: ${cameraPosition.x.toFixed(2)} Y: ${cameraPosition.y.toFixed(2)} Z: ${cameraPosition.z.toFixed(2)}`;
}// 更新FPS显示
let frameCount = 0;
let prevTime = performance.now();
function updateFPS() {frameCount++;const currentTime = performance.now();if (currentTime - prevTime >= 1000) {const fps = Math.round((frameCount * 1000) / (currentTime - prevTime));document.getElementById('fps-display').textContent = `FPS: ${fps}`;frameCount = 0;prevTime = currentTime;}
}// 添加机器人关节
function addJoint(type, position) {const geometry = new THREE.SphereGeometry(0.2, 32, 32);const material = new THREE.MeshStandardMaterial({ color: 0xff5722 });const joint = new THREE.Mesh(geometry, material);joint.position.copy(position || new THREE.Vector3(0, 0, 0));joint.userData.isJoint = true;joint.userData.type = type || 'revolute';joint.userData.range = 90;joint.userData.speed = 1;joint.userData.angle = 0;scene.add(joint);robot.joints.push(joint);updateModelInfo();return joint;
}// 添加机器人连杆
function addLink(startJoint, endJoint) {if (!startJoint || !endJoint) return null;// 计算连杆位置和方向const start = startJoint.position.clone();const end = endJoint.position.clone();const direction = end.clone().sub(start);const length = direction.length();// 创建连杆几何体const geometry = new THREE.CylinderGeometry(0.1, 0.1, length, 16);geometry.translate(0, length / 2, 0);// 创建连杆材质const material = new THREE.MeshStandardMaterial({ color: 0x2196F3 });const link = new THREE.Mesh(geometry, material);// 设置连杆位置和旋转link.position.copy(start);link.lookAt(end);link.rotateX(Math.PI / 2);// 设置连杆的自定义数据link.userData.isLink = true;link.userData.startJoint = startJoint;link.userData.endJoint = endJoint;scene.add(link);robot.parts.push(link);updateModelInfo();return link;
}// 更新模型信息显示
function updateModelInfo() {document.getElementById('model-info').textContent = `零件: ${robot.parts.length} | 关节: ${robot.joints.length}`;
}// 选择对象
function selectObject(object) {if (selectedObject === object) return;// 取消先前选择的对象if (selectedObject) {if (selectedObject.material && selectedObject.material.emissive) {selectedObject.material.emissive.setHex(0x000000);}}// 设置新选择的对象selectedObject = object;if (selectedObject) {// 高亮选中的对象if (selectedObject.material && selectedObject.material.emissive) {selectedObject.material.emissive.setHex(0x333333);}// 应用变换控制器transformControls.attach(selectedObject);// 更新属性面板updatePropertiesPanel();} else {transformControls.detach();document.getElementById('selected-item-name').textContent = '无';}
}// 更新属性面板
function updatePropertiesPanel() {if (!selectedObject) return;// 更新选中项目名称let itemName = selectedObject.userData.isJoint ? '关节' : selectedObject.userData.isLink ? '连杆' : '物体';document.getElementById('selected-item-name').textContent = itemName;// 更新位置document.getElementById('position-x').value = selectedObject.position.x.toFixed(2);document.getElementById('position-y').value = selectedObject.position.y.toFixed(2);document.getElementById('position-z').value = selectedObject.position.z.toFixed(2);// 更新旋转(转换为度数)const rotation = selectedObject.rotation.toArray().slice(0, 3).map(rad => (rad * 180 / Math.PI).toFixed(0));document.getElementById('rotation-x').value = rotation[0];document.getElementById('rotation-y').value = rotation[1];document.getElementById('rotation-z').value = rotation[2];// 更新尺寸document.getElementById('scale').value = selectedObject.scale.x.toFixed(1);// 更新材质颜色if (selectedObject.material && selectedObject.material.color) {const color = '#' + selectedObject.material.color.getHexString();document.getElementById('material-color').value = color;}// 更新关节特有的属性const jointProperties = document.querySelectorAll('.joint-property');if (selectedObject.userData.isJoint) {jointProperties.forEach(el => el.style.display = 'flex');// 更新关节类型document.getElementById('joint-type').value = selectedObject.userData.type || 'revolute';// 更新关节范围document.getElementById('joint-range').value = selectedObject.userData.range || 90;document.getElementById('joint-range-value').textContent = `${selectedObject.userData.range || 90}°`;// 更新关节速度document.getElementById('joint-speed').value = selectedObject.userData.speed || 1;} else {jointProperties.forEach(el => el.style.display = 'none');}
}// 更新模型参数
function updateModelParameters() {if (!selectedObject) return;// 更新位置selectedObject.position.set(parseFloat(document.getElementById('position-x').value),parseFloat(document.getElementById('position-y').value),parseFloat(document.getElementById('position-z').value));// 更新旋转(转换为弧度)selectedObject.rotation.set(parseFloat(document.getElementById('rotation-x').value) * Math.PI / 180,parseFloat(document.getElementById('rotation-y').value) * Math.PI / 180,parseFloat(document.getElementById('rotation-z').value) * Math.PI / 180);// 更新尺寸const scale = parseFloat(document.getElementById('scale').value);selectedObject.scale.set(scale, scale, scale);// 更新材质颜色if (selectedObject.material && selectedObject.material.color) {const color = document.getElementById('material-color').value;selectedObject.material.color.set(color);}// 对于关节,更新特有属性if (selectedObject.userData.isJoint) {selectedObject.userData.type = document.getElementById('joint-type').value;selectedObject.userData.range = parseInt(document.getElementById('joint-range').value);selectedObject.userData.speed = parseFloat(document.getElementById('joint-speed').value);document.getElementById('joint-range-value').textContent = `${selectedObject.userData.range}°`;}// 如果是连杆,可能需要更新其几何形状if (selectedObject.userData.isLink) {updateLinkGeometry(selectedObject);}
}// 更新连杆几何形状
function updateLinkGeometry(link) {if (!link.userData.isLink) return;const startJoint = link.userData.startJoint;const endJoint = link.userData.endJoint;if (!startJoint || !endJoint) return;// 计算连杆位置和方向const start = startJoint.position.clone();const end = endJoint.position.clone();const direction = end.clone().sub(start);const length = direction.length();// 创建新的几何体const newGeometry = new THREE.CylinderGeometry(0.1, 0.1, length, 16);newGeometry.translate(0, length / 2, 0);// 更新几何体和位置link.geometry.dispose();link.geometry = newGeometry;link.position.copy(start);link.lookAt(end);link.rotateX(Math.PI / 2);
}// 删除选中的部件
function deleteSelectedPart() {if (!selectedObject) return;// 从场景中移除scene.remove(selectedObject);// 从机器人数据中移除if (selectedObject.userData.isJoint) {const index = robot.joints.indexOf(selectedObject);if (index !== -1) robot.joints.splice(index, 1);// 同时要移除与该关节连接的所有连杆const connectedLinks = robot.parts.filter(part => part.userData.isLink && (part.userData.startJoint === selectedObject || part.userData.endJoint === selectedObject));connectedLinks.forEach(link => {scene.remove(link);const linkIndex = robot.parts.indexOf(link);if (linkIndex !== -1) robot.parts.splice(linkIndex, 1);});} else if (selectedObject.userData.isLink) {const index = robot.parts.indexOf(selectedObject);if (index !== -1) robot.parts.splice(index, 1);}// 更新模型信息updateModelInfo();// 清除选择transformControls.detach();selectedObject = null;document.getElementById('selected-item-name').textContent = '无';
}// 开始运动仿真
function startSimulation() {if (isSimulating) return;isSimulating = true;currentTime = 0;clock.start();document.getElementById('play-btn').disabled = true;document.getElementById('pause-btn').disabled = false;
}// 暂停运动仿真
function pauseSimulation() {if (!isSimulating) return;isSimulating = false;clock.stop();document.getElementById('play-btn').disabled = false;document.getElementById('pause-btn').disabled = true;
}// 重置运动仿真
function resetSimulation() {pauseSimulation();currentTime = 0;document.getElementById('current-time').textContent = '0.00';// 重置所有关节的角度robot.joints.forEach(joint => {joint.userData.angle = 0;joint.rotation.set(0, 0, 0);});// 更新连杆位置updateLinksPosition();
}// 更新仿真状态
function updateSimulation() {const deltaTime = clock.getDelta();currentTime += deltaTime;document.getElementById('current-time').textContent = currentTime.toFixed(2);// 更新所有关节的旋转robot.joints.forEach(joint => {if (joint.userData.type === 'revolute') {// 针对旋转关节,围绕Y轴旋转const maxAngle = joint.userData.range * Math.PI / 180;const speed = joint.userData.speed;// 简单的正弦函数模拟往复运动joint.userData.angle = Math.sin(currentTime * speed) * maxAngle;joint.rotation.y = joint.userData.angle;} else if (joint.userData.type === 'prismatic') {// 针对移动关节,在Y轴方向移动const range = joint.userData.range / 100; // 转换为合适的移动距离const speed = joint.userData.speed;// 简单的正弦函数模拟往复运动const offset = Math.sin(currentTime * speed) * range;// 保存初始位置if (joint.userData.initialPosition === undefined) {joint.userData.initialPosition = joint.position.clone();}// 根据初始位置计算当前位置joint.position.y = joint.userData.initialPosition.y + offset;}});// 更新连杆的位置updateLinksPosition();
}// 更新所有连杆的位置
function updateLinksPosition() {robot.parts.forEach(part => {if (part.userData.isLink) {updateLinkGeometry(part);}});
}// 添加关键帧
function addKeyframe() {const time = currentTime;// 创建关键帧对象const keyframe = {time: time,joints: robot.joints.map(joint => ({id: joint.id,angle: joint.userData.angle}))};// 添加到关键帧列表keyframes.push(keyframe);// 在时间轴上显示关键帧const timelineTrack = document.getElementById('timeline-track');const marker = document.createElement('div');marker.className = 'keyframe-marker';marker.style.left = `${(time / 10) * 100}%`;marker.title = `时间: ${time.toFixed(2)}s`;timelineTrack.appendChild(marker);
}// 创建示例机器人模型
function createExampleRobot() {// 创建基座const baseGeometry = new THREE.CylinderGeometry(0.5, 0.5, 0.2, 32);const baseMaterial = new THREE.MeshStandardMaterial({ color: 0x333333 });const base = new THREE.Mesh(baseGeometry, baseMaterial);base.position.y = 0.1;scene.add(base);robot.parts.push(base);// 创建第一个关节(肩部)const shoulderJoint = addJoint('revolute', new THREE.Vector3(0, 0.3, 0));// 创建第二个关节(肘部)const elbowJoint = addJoint('revolute', new THREE.Vector3(0, 0.3, 1.5));// 创建第三个关节(腕部)const wristJoint = addJoint('revolute', new THREE.Vector3(0, 0.3, 3));// 创建连杆addLink(shoulderJoint, elbowJoint);addLink(elbowJoint, wristJoint);// 创建机械手const gripperGeometry = new THREE.BoxGeometry(0.5, 0.1, 0.5);const gripperMaterial = new THREE.MeshStandardMaterial({ color: 0x4caf50 });const gripper = new THREE.Mesh(gripperGeometry, gripperMaterial);gripper.position.copy(wristJoint.position);gripper.position.z += 0.3;scene.add(gripper);robot.parts.push(gripper);// 创建地面const groundGeometry = new THREE.PlaneGeometry(20, 20);const groundMaterial = new THREE.MeshStandardMaterial({ color: 0xeeeeee,side: THREE.DoubleSide,transparent: true,opacity: 0.5});const ground = new THREE.Mesh(groundGeometry, groundMaterial);ground.rotation.x = Math.PI / 2;ground.position.y = -0.1;ground.receiveShadow = true;scene.add(ground);// 更新模型信息updateModelInfo();
}// 初始化事件监听器
function initEventListeners() {// 画布点击事件document.getElementById('robot-canvas').addEventListener('click', onCanvasClick);// 属性面板输入变更事件document.querySelectorAll('.property-row input, .property-row select').forEach(element => {element.addEventListener('change', updateModelParameters);});// 工具栏按钮点击事件document.getElementById('add-joint-btn').addEventListener('click', () => {const joint = addJoint('revolute', new THREE.Vector3(0, 0, 0));selectObject(joint);});document.getElementById('add-link-btn').addEventListener('click', () => {if (robot.joints.length < 2) {alert('需要至少两个关节才能添加连杆!');return;}// 简化实现,默认连接第一个和第二个关节const link = addLink(robot.joints[0], robot.joints[1]);if (link) selectObject(link);});document.getElementById('delete-part-btn').addEventListener('click', deleteSelectedPart);// 仿真控制按钮document.getElementById('play-btn').addEventListener('click', startSimulation);document.getElementById('pause-btn').addEventListener('click', pauseSimulation);document.getElementById('reset-btn').addEventListener('click', resetSimulation);// 关键帧按钮document.getElementById('add-keyframe-btn').addEventListener('click', addKeyframe);// 画布控制按钮document.getElementById('zoom-in-btn').addEventListener('click', () => {camera.position.multiplyScalar(0.9);});document.getElementById('zoom-out-btn').addEventListener('click', () => {camera.position.multiplyScalar(1.1);});document.getElementById('rotate-btn').addEventListener('mousedown', () => {controls.enableRotate = true;controls.enablePan = false;});document.getElementById('pan-btn').addEventListener('mousedown', () => {controls.enableRotate = false;controls.enablePan = true;});// 保存/加载模型按钮document.getElementById('save-model-btn').addEventListener('click', saveModel);document.getElementById('load-model-btn').addEventListener('click', loadModel);document.getElementById('new-model-btn').addEventListener('click', newModel);
}// 保存模型
function saveModel() {// 将机器人数据序列化const modelData = {parts: robot.parts.map(part => {return {type: part.userData.isLink ? 'link' : 'part',position: part.position.toArray(),rotation: part.rotation.toArray(),scale: part.scale.toArray(),color: part.material ? part.material.color.getHex() : 0xffffff,// 对于连杆,存储其所连接的关节的索引startJointIndex: part.userData.startJoint ? robot.joints.indexOf(part.userData.startJoint) : -1,endJointIndex: part.userData.endJoint ? robot.joints.indexOf(part.userData.endJoint) : -1};}),joints: robot.joints.map(joint => {return {type: joint.userData.type,position: joint.position.toArray(),rotation: joint.rotation.toArray(),range: joint.userData.range,speed: joint.userData.speed};})};// 转换为JSON字符串const jsonString = JSON.stringify(modelData, null, 2);// 在实际环境中,这里可能会使用Appsmith的存储API// 在此示例中,我们使用本地下载const blob = new Blob([jsonString], { type: 'application/json' });const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'robot-model.json';a.click();URL.revokeObjectURL(url);
}// 加载模型
function loadModel() {// 在实际环境中,这里可能会使用Appsmith的存储API// 在此示例中,我们使用文件上传const input = document.createElement('input');input.type = 'file';input.accept = '.json';input.onchange = (event) => {const file = event.target.files[0];if (!file) return;const reader = new FileReader();reader.onload = (e) => {try {const modelData = JSON.parse(e.target.result);loadModelFromData(modelData);} catch (error) {console.error('加载模型失败:', error);alert('加载模型失败,文件格式可能不正确。');}};reader.readAsText(file);};input.click();
}// 从数据中加载模型
function loadModelFromData(modelData) {// 清除当前模型newModel();// 首先加载关节modelData.joints.forEach(jointData => {const joint = addJoint(jointData.type, new THREE.Vector3().fromArray(jointData.position));joint.rotation.fromArray(jointData.rotation);joint.userData.range = jointData.range;joint.userData.speed = jointData.speed;});// 然后加载部件modelData.parts.forEach(partData => {if (partData.type === 'link' && partData.startJointIndex !== -1 && partData.endJointIndex !== -1) {// 加载连杆const startJoint = robot.joints[partData.startJointIndex];const endJoint = robot.joints[partData.endJointIndex];if (startJoint && endJoint) {const link = addLink(startJoint, endJoint);if (link) {link.material.color.setHex(partData.color);}}} else {// 加载其他部件(如基座等)// 这部分在完整实现中需要根据部件类型来创建不同的几何体const geometry = new THREE.BoxGeometry(1, 1, 1);const material = new THREE.MeshStandardMaterial({ color: partData.color });const part = new THREE.Mesh(geometry, material);part.position.fromArray(partData.position);part.rotation.fromArray(partData.rotation);part.scale.fromArray(partData.scale);scene.add(part);robot.parts.push(part);}});// 更新模型信息updateModelInfo();
}// 新建模型
function newModel() {// 清除所有部件和关节[...robot.parts, ...robot.joints].forEach(object => {if (object.geometry) object.geometry.dispose();if (object.material) {if (Array.isArray(object.material)) {object.material.forEach(mat => mat.dispose());} else {object.material.dispose();}}scene.remove(object);});// 重置数据robot.parts = [];robot.joints = [];keyframes = [];// 清除关键帧标记document.getElementById('timeline-track').innerHTML = '';// 清除选择transformControls.detach();selectedObject = null;document.getElementById('selected-item-name').textContent = '无';// 重置仿真状态resetSimulation();// 更新模型信息updateModelInfo();
}// 画布点击事件处理
function onCanvasClick(event) {// 计算鼠标在画布中的归一化坐标const rect = renderer.domElement.getBoundingClientRect();mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;// 射线投射选择对象raycaster.setFromCamera(mouse, camera);const intersects = raycaster.intersectObjects(scene.children, true);if (intersects.length > 0) {// 查找第一个可选择的对象(关节或连杆)const selectable = intersects.find(intersect => intersect.object.userData.isJoint || intersect.object.userData.isLink);if (selectable) {selectObject(selectable.object);} else {selectObject(null);}} else {selectObject(null);}
}
相关文章:
7、三维机械设计、装配与运动仿真组件 - /设计与仿真组件/3d-mechanical-designer
76个工业组件库示例汇总 三维机械设计、装配与运动仿真通用组件 这是一个基于Three.js开发的三维机械设计、装配与运动仿真通用组件,可以实现工业机器人关节结构设计与运动仿真功能。 功能特点 直观的三维设计界面:提供基于WebGL的3D设计空间&#x…...
传统数据展示 vs 可视化:谁更打动人心?
数据,每天都在我们身边流动:从你手机里的健康步数,到企业财报中的营收增长,再到国家发布的经济指标。但问题是——你怎么“看”这些数据? 过去,我们习惯用表格、文字和报告来展示数据,这种方式…...
CSdiy java 07
1 || 运用逻辑运算符 在 Java 代码里,|| 是逻辑或(Logical OR)运算符,它的作用是对两个布尔表达式进行逻辑或运算。下面结合具体的代码片段来详细说明: 一、|| 的基本含义 在 Java 中,|| 运算符遵循以下…...
从零打造企业级Android木马:数据窃取与远程控制实战
简介 木马病毒已从简单的恶意软件演变为复杂的攻击工具,尤其在2025年企业级攻击中,木马病毒正成为黑客组织的主要武器之一。 本文将深入探讨如何制作具备数据窃取和远程控制功能的Android木马,从基础原理到企业级防御绕过技术,同时提供详细的代码实现,帮助开发者理解木马…...
金仓数据库永久增量备份技术原理与操作
先用一张图说明一下常见的备份方式 为什么需要永久增量备份 传统的数据库备份方案通常是间隔7天对数据库做一次全量备份(完整备份),每天会基于全量备份做一次增量备份,如此循环,这种备份方案在全备数据量过大场景下…...
为特定领域微调嵌入模型:打造专属的自然语言处理利器
🧠 向所有学习者致敬! “学习不是装满一桶水,而是点燃一把火。” —— 叶芝 我的博客主页: https://lizheng.blog.csdn.net 🌐 欢迎点击加入AI人工智能社区! 🚀 让我们一起努力,共创…...
SQLite 转换为 MySQL 数据库
一、导出 SQLite 数据库 1. 使用 SQLite 命令行工具 • 打开终端(在 Linux 或 macOS 上)或命令提示符(在 Windows 上)。 • 输入sqlite3 your_database_name.db(将 your_database_name.db 替换为你的 SQLite 数据库…...
cnas软件检测实验室质量管理体系文件思维导图,快速理清全部文件
软件检测实验室在申请CNAS资质时,需要根据认可文件的要求,建立实验室质量管理体系,明晰地展示组织架构、合理地安排人员岗位职责和能力要求、全面地覆盖认可文件要求的质量要素。这是一项非常庞大的工作,涉及到的文件类型非常多&a…...
31【干货】Arcgis属性表常用查询表达式实战大全
GIS数据属性表的查询在工作中常常用到,本文对常见的基本运算符进行详细介绍,并以实例的形式,针对SQL查询常用的语句进行实例分类解析,大家可以结合项目需求,自行更改对应的语句,提高工作效率。特别注意文末…...
uniapp 不同路由之间的区别
在UniApp中,路由跳转是实现页面导航的核心功能,常见的路由跳转方式包括navigateTo、redirectTo、reLaunch、switchTab和navigateBack。这些方法在跳转行为和适用场景上有所不同。 一、路由跳转的类型与区别 1. uni.navigateTo(OBJECT) 特点࿱…...
前台--Android开发
在 Android 开发中,“前台(Foreground)” 是一个非常重要的概念,它用于描述当前用户正在与之交互的组件或应用状态。理解“前台”的含义有助于更好地管理资源、生命周期和用户体验。 ✅ 一、什么是前台? 简单定义&…...
python: update() 函数的用法和例子
Python 中 update() 函数的用法和例子 在 Python 中,update() 函数通常用于字典(dictionary)对象,以更新其键值对。该函数会将另一个字典或可迭代对象中的元素添加到当前字典中,如果键已经存在,则覆盖对应…...
动态规划-62.不同路径-力扣(LeetCode)
一、题目解析 机器人只能向下或向左,要从Start位置到Finish位置。 二、算法原理 1.状态表示 我们要求到Finish位置一共有多少种方法,记Finish为[i,j],此时dp[i,j]表示:到[i,j]位置时,一共有多少种方法,满…...
排序算法总结
在讲解排序算法之前,我们需要先了解一下排序 所谓排序,就是将数据按照我们的想法将其按照一定规律组合在一起 稳定性:一组数据中的数据是否在排序前后都保持的一定的前后顺序关系,比如在排序前a[3]2 a[5]2,这时他们有着…...
kafka学习笔记(四、生产者、消费者(客户端)深入研究(三)——事务详解及代码实例)
1.事务简介 Kafka事务是Apache Kafka在流处理场景中实现Exactly-Once语义的核心机制。它允许生产者在跨多个分区和主题的操作中,以原子性(Atomicity)的方式提交或回滚消息,确保数据处理的最终一致性。例如,在流处理中…...
【Git】查看tag
文章目录 1. 查看当前提交是否有tag2. 查看最近的tag3. 查看所有tag 有时候需要基于某个tag拉分支,记录下怎么查看tag。 1. 查看当前提交是否有tag git tag --points-at HEAD该命令可直接检查当前提交(HEAD)是否关联了任何tag。 若当前提交…...
开源数字人框架 AWESOME - DIGITAL - HUMAN:技术革新与行业标杆价值剖析
一、项目核心价值:解锁数字人技术新境界 1. 技术普及:降低准入门槛,推动行业民主化 AWESOME - DIGITAL - HUMAN 项目犹如一场技术春雨,为数字人领域带来了普惠甘霖。它集成了 ASR、LLM、TTS 等关键能力,并提供模块化扩展接口,将原本复杂高深的数字人开发流程,转化为一…...
Android系统架构模式分析
本文系统梳理Android系统架构模式的演进路径与设计哲学,希望能够借此探索未来系统的发展方向。有想法的同学可以留言讨论。 1 Android层次化架构体系 1.1 整体分层架构 Android系统采用五层垂直架构,各层之间通过严格接口定义实现解耦: 应用…...
【MYSQL错误连接太多】
com.mysql.cj.exceptions.CJException: null, message from server: "Host 192.168.0.200 is blocked because of many connection errors; unblock with mysqladmin flush-hosts"方法一:通过配置文件永久更改 找到你的 MySQL 配置文件(通常…...
C23 与 MISRA C:2025:嵌入式 C 语言的进化之路
引言 在 Rust、Go 等现代语言蓬勃发展的今天,C 语言依然以 27.7% 的 TIOBE 指数(2024 年 6 月数据)稳居编程语言前三甲。其核心竞争力不仅在于高效的底层控制能力,更在于持续进化的标准体系。2024 年发布的 C23(ISO/I…...
HunyuanCustom, 腾讯混元开源的多模态定制视频生成框架
HunyuanCustom是一款由腾讯混元团队开发的多模态驱动定制视频生成框架,能够支持图像、音频、视频和文本等多种输入方式。该框架专注于生成高质量的视频,能够实现特定主体和场景的精准呈现。 HunyuanCustom是什么 HunyuanCustom是腾讯混元团队推出的一种…...
el-menu 折叠后小箭头不会消失
官方示例 <template><el-radio-group v-model"isCollapse" style"margin-bottom: 20px"><el-radio-button :value"false">expand</el-radio-button><el-radio-button :value"true">collapse</el-ra…...
Spring Boot中的拦截器!
每次用户请求到达Spring Boot服务端,你是否需要重复写日志、权限检查或请求格式化代码?这些繁琐的“前置后置”工作让人头疼!好在,Spring Boot拦截器如同一道智能关卡,统一处理请求的横切逻辑,让代码优雅又…...
Docker宿主机IP获取
1.Linux: ip addr show docker0 2. macOS/Windows 环境(Docker Desktop) 在Docker Desktop中,宿主机(你的物理机)通过host.docker.internal主机名暴露给容器,无需手动查找IP。 方法1:在容器…...
Flink之Table API
Apache Flink 的 Table API 是 Flink 提供的一种高级抽象,用于以声明式方式处理批处理和流处理数据。它是基于关系模型的 API,用户可以像编写 SQL 一样,以简洁、类型安全的方式编写数据处理逻辑。 一、基本概念 1. 什么是 Table API…...
Kubernetes生产实战:NodePort端口范围的隐藏规则与调优指南
在Kubernetes中暴露服务时,很多开发者第一次看到NodePort的端口号都会惊呼:"为什么我的服务被分配了3万多的端口?"。这背后隐藏着Kubernetes设计者的深思熟虑,今天我们就来揭开这个"数字谜团"。 一、默认端口…...
读取传感器发来的1Byte数据:分低位先行和高位先行的处理方法
目录 一、写在前面 二、伪代码的逻辑实现 1、从高位到低位 2、从低位到高位 一、写在前面 在接收数据之前我们需要事先知道数据的发送规则,是高位先行还是低位先行,并按照规则接收数据,否则收到的数据很可能是错的 高位先行:…...
在 Ubuntu 上安装并运行 ddns-go 教程
在 Ubuntu 上安装并运行 ddns-go 教程 什么是 ddns-go? ddns-go 是一款开源的轻量级 DDNS(动态域名解析)客户端,支持多家 DNS 服务商(如阿里云、腾讯云、Cloudflare、Dnspod 等),适合在家用宽…...
2025.05.07-淘天算法岗-第三题
📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 03. 信号增强最小操作次数 问题描述 卢小姐正在进行一项信号处理实验。她有一个长度为 n n n...
边缘大型语言模型综述:设计、执行和应用
(2025-08-31) A Review on Edge Large Language Models: Design, Execution, and Applications (Edge 大型语言模型综述:设计、执行和应用) 作者: Yue Zheng; Yuhao Chen; Bin Qian; Xiufang Shi; Yuanchao Shu; Jiming Chen;期刊: ACM Computing Surveys (发表日期: 2025-08…...
谷云科技iPaaS发布 MCP Server加速业务系统API 跨入 MCP 时代
在数字化浪潮中,集成技术与 AI 技术的融合成为企业智能化转型的关键。谷云科技作为 iPaaS 集成技术领域的佼佼者,我们率先在iPaaS中全新推出 MCP Server,这不仅是对谷云科技现有产品线的有力补充,更是我们顺应 AI 发展潮流、深化集…...
rabbitmq学习笔记快速使用
主要是快速了解使用,对于强要求比如说数据安全(也就是spring配置先不要求) 那么开始 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>…...
PMIC电源管理模块的PCB设计
目录 PMU模块简介 PMU的PCB设计 PMU模块简介 PMIC(电源管理集成电路)是现代电子设备的核心模块,负责高效协调多路电源的转换、分配与监控。它通过集成DC-DC降压/升压、LDO线性稳压、电池充电管理、功耗状态切换等功能,替代传统分…...
云原生CAE软件
云原生CAE软件是一种在设计和实现时就充分考虑了云环境特点的软件,能够充分利用云资源,实现高效、可扩展和灵活的仿真分析。 定义和特点 云原生CAE软件是一种在云端构建和运行的CAE(Computer Aided Engineering,计算机辅助工…...
计算机视觉】OpenCV项目实战:eye_mouse_movement:基于opencv实战眼睛控制鼠标
eye_mouse_movement:基于视觉追踪的实时眼控交互系统 一、项目概述与技术背景1.1 项目核心价值1.2 技术指标对比1.3 技术演进路线 二、环境配置与系统部署2.1 硬件要求2.2 软件安装基础环境搭建关键组件说明 2.3 模型文件部署 三、核心算法解析3.1 系统架构设计3.2 …...
《大规模电动汽车充换电设施可调能力聚合评估与预测》MATLAB实现计划
模型概述 根据论文,我将复刻实现结合长短期记忆网络(LSTM)和条件变分自编码器(CVAE)的预测方法,用于电动汽车充换电设施可调能力的聚合评估与预测。 实现步骤 1. 数据预处理 导入充电数据 (Charging_Data.csv)导入天气数据 (Weather_Data.csv)导入电…...
【C++进阶】第2课—多态
文章目录 1. 认识多态2. 多态的定义和实现2.1 构成多态的必要条件2.2 虚函数2.3 虚函数的重写或覆盖2.4 协变(了解)2.5 析构函数的重写2.6 override和final关键字2.7 重载、重写、隐藏对比 3. 纯虚函数和抽象类4. 多态原理4.1 虚函数表指针4.2 多态的实现4.3 静态绑定和动态绑定…...
Mysql--基础知识点--91.2--processlist
在 MySQL 中,SHOW PROCESSLIST 是一个常用命令,用于查看当前数据库服务器上所有正在运行的线程(进程)信息。以下是关键点说明: 1. 命令用法 SHOW FULL PROCESSLIST;输出字段: 列名含义Id线程唯一标识符&am…...
【阿里云免费领取域名以及ssl证书,通过Nginx反向代理web服务】
文章目录 前言一、申请域名1.1 访问阿里云官网1.2 输入自定义域名1.3 创建个人模板1.4 支付1元可以使用域名1年1.5 按照提示实名认证1.6 实名认证成功 二、域名解析2.1 选择域名解析2.2 解析设置2.3 快速添加解析2.4 选择对应类型2.5 解析成功 三、申请免费ssl证书3.1 访问阿里…...
Mamba 状态空间模型 笔记 llm框架 一维卷积
动画讲解 Mamba 状态空间模型_哔哩哔哩_bilibili 旧文本向量乘权重加残差 感觉好像transformer 过个llm head输出y 卷积真的很快 参考一文通透想颠覆Transformer的Mamba:从SSM、HiPPO、S4到Mamba(被誉为Mamba最佳解读)_mamba模型-CSDN博客 偷了 Transformer的二次复…...
WPF内嵌其他进程的窗口
WPF内嵌其他进程窗口的常见方法有 HwndHost SetParent 和 WindowsFormsHost WinForms Panel SetParent 推荐使用自定义HwndHost 两者的对比区别 示例代码 public class MyWndHost : HwndHost {const int WS_CHILD 0x40000000;const int WS_VISIBLE 0x10000000;const i…...
1、mongodb-- BSON 学习和JSON性能对比
BSON 是什么 MongoDB 作为一款流行的文档数据库,采用 BSON 格式来支持文档模型。 BSON 全称是 Binary JSON,和 JSON 很像,但是采用二进制格式进行存储。相比 JSON 有以下优势: 访问速度更快:BSON 会存储 Value 的类…...
19、HashTable(哈希)、位图的实现和布隆过滤器的介绍
一、了解哈希【散列表】 1、哈希的结构 在STL中,HashTable是一个重要的底层数据结构, 无序关联容器包括unordered_set, unordered_map内部都是基于哈希表实现 哈希表又称散列表,一种以「key-value」形式存储数据的数据结构。哈希函数:负责将…...
鱼眼摄像头(一)多平面格式 单缓冲读取图像并显示
鱼眼摄像头(一)多平面格式 单缓冲读取图像并显示 1.摄像头格式 1. 单平面格式(Single Plane):各通道数据保存在同一个平面(缓冲),图像数据按行连续存储a. mjpeg,yuyv等…...
wpf UserControl 更换 自定义基类
在WPF中实现UserControl更换自定义基类的操作,需注意以下关键步骤及注意事项 实现步骤 创建自定义基类 新建继承自UserControl的基类(如CustomBaseUserControl),并添加通用逻辑: public class BaseUserControl: UserControl {// 添加共享逻辑(如事件处理、初始化…...
Linux C语言线程编程入门笔记
目录 开发环境准备 线程基础概念 进程与线程的关系 线程生命周期 创建线程 等待线程结束 线程函数和参数 互斥锁与共享资源保护 总结 开发环境准备 操作系统:以 Linux 为例(Ubuntu/CentOS 等主流发行版)。请确保系统已安装 GNU C 编…...
网络安全体系架构:核心框架与关键机制解析
以下是关于网络安全体系架构设计相关内容的详细介绍: 一、开放系统互联安全体系结构 开放系统互联(OSI)安全体系结构是一种基于分层模型的安全架构,旨在为开放系统之间的通信提供安全保障。它定义了安全服务、安全机制以及它们在…...
SecureCRT网络穿透/代理
场景 公司的办公VPN软件只有Windows系统版本,没有Macos系统版本,而日常开发过程中需要先登录VPN后,然后才能登录应用服务器。 目的:Macos系统在使用SecureCRT时,登录服务器,需要走Parallels Desktop进行网络…...
Typora+PicGo+Gitee图床配置教程 自动图片上传
配置步骤 #mermaid-svg-aPUbWs43XR5Rh7vf {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-aPUbWs43XR5Rh7vf .error-icon{fill:#552222;}#mermaid-svg-aPUbWs43XR5Rh7vf .error-text{fill:#552222;stroke:#552222;}#…...
基于vue框架的电子商城m8qu8(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
系统程序文件列表 项目功能:用户,商品类型,商品信息,商城公告 开题报告内容 基于Vue框架的电子商城开题报告 一、研究背景与意义 随着互联网技术的飞速发展,电子商务已成为全球商业领域的重要增长点。根据艾瑞咨询数据,中国网络购物用户规…...