node 即为需要看向某一个点的节点,position 为看向的点的坐标,第二个参数有六个枚举值可以选择,分别为 bottom,back,front,top,right,left,第二个参数的作用是当我们需要把某个物体看向某一个点的时候我们也要指定该物体的哪一个面看向该点,所以需要提供第二个参数来明确,获取到该函数之后我们可以通过将 bucketHinge 看向点 P,armHinge 看向点 P,就可以保持这两个连接的设备永远朝向该点,以下为部分伪代码:
在场景中我们可以看到液压主要分为两个部分,一部分为白色的较细的液压杆,一部分为黑色的较厚的液压杆,白色的液压杆插在黑色的液压杆中,所以在小臂或者挖斗旋转的过程中我们要保持两个节点始终保持相对的位置,通过上一步骤中我们可以知道 lookAtX 这个函数的作用,所以在液压杆部分我们也是照样用该函数来实现。
在上一步我们获取到了挖斗旋转过程中的关键点 P,所以在挖斗旋转的过程我们小臂上的液压杆也要相应的进行变化,具体的操作就是将小臂的白色液压杆的位置设置为上步中计算出来的点 P 的位置,当然需要把白色液压杆的锚点进行相应的设置,之后让白色液压杆 lookAt 黑色液压杆,同时让黑色液压杆 lookAt 白色液压杆,这样下来两个液压杆都在互相看著对方,所以它们呈现出来的效果就是白色液压杆在黑色液压杆中进行伸缩,以下为伪代码:
同理挖机身上的大臂的液压动作以及机身与大臂连接部分的液压动作都是使用上面的方法来实现,以下为这两部分的代码:
rotateBoom: (rotateVal) = >{
excavatorBoomNode.setRotationX(dr * rotateVal);
let archorVector = [0.5 - 0.5, 0.56 - 0.5, 0.22 - 0.5];
let pos = projectUtil.toWorldPosition(g3d, excavatorBoomNode, archorVector);
boomWhite.lookAtX(boomBlack.p3(), bottom);
boomBlack.lookAtX(pos, top);
},
rotateArm: (rotateVal) = >{
projectUtil.applyRelativeRotation(excavatorArmNode, excavatorBoomNode, -rotateVal);
let archorVector = [0.585 - 0.5, 0.985 - 0.5, 0.17 - 0.5];
let pos = projectUtil.toWorldPosition(g3d, excavatorArmNode, archorVector);
armWhite.lookAtX(armBlack.p3(), bottom);
armBlack.lookAtX(pos, top);
我将两部分的运动封装为两个函数 rotateBoom 以及 rotateArm 分别是大臂与机身连接处的液压运动与大臂上的液压运动,在该部分中为了精确的获取看向的点,我通过 toWorldPosition 方法将相对坐标转化为世界坐标,相对坐标为黑白液压杆的锚点坐标,转化为相对大臂或者机身的世界坐标。
基本运动分析
挖机的基本运动包括前进后退,机身旋转,这一部分会相对上面的运动简单许多,在 HT 的三维坐标系中,不断修改挖机机身的 x,y,z 的坐标值就可以实现挖机的前进后退,通过修改机身的 y 轴旋转角度则可以控制机身的旋转,当然挖机身体上的所有其它零部件需要吸附在机身身上,当机身进行旋转时其它零部件则会进行相应的旋转,在进行前进的时候挖机底部的履带会进行对应的滚动,当然履带我们这边是用了一个履带的贴图贴在上面,当挖机前进的时候修改贴图的偏移值就可以实现履带的滚动,修改偏移值的伪代码如下:
node.s(shape3d.uv.offset, [x, y]);
上面的 x,y 分别为 x 轴与 y 轴方向的偏移值,在挖机前进后退的过程中不断修改 y 的值可以实现履带的滚动效果,具体的文档说明可以查看 3D手册
在挖机前进后退的过程中我们可以 wasd 四个键同时按下,并且可以对按键进行一直的响应,在 js 中可以通过 document.addEventListener(keydown, (e) => {}) 以及 document.addEventListener(keyup, (e) => {}) 进行监听,但是这只能每次执行一次需要执行的动作,所以我们可以在外部起一个定时器,来执行 keydown 时候需要不断执行的动作,可以用一个 keyMap 来记录当前已经点击的按键,在 keydown 的时候纪录为 true 在 keyup 的时候记录为 false,所以我们可以在定时器中判断这个 bool 值,当为 true 的时候则执行相应的动作,否则不执行,以下为对应的部分关键代码:
let key_pressed = {
65 : {
status: false,
action: turnLeft
},
87 : {
status: false,
action: goAhead
},
68 : {
status: false,
action: turnRight
},
83 : {
status: false,
action: back
},
37 : {
status: false,
action: bodyTurnLeft
},
39 : {
status: false,
action: bodyTurnRight
}
};
setInterval(() = >{
for (let key in key_pressed) {
let {
status,
action
} = key_pressed[key];
if (status) {
action();
}
}
},
50);
document.addEventListener(keydown, (event) = >{
let keyCode = event.keyCode;
key_pressed[keyCode] && (key_pressed[keyCode].status = true);
event.stopPropagation();
},
true);
document.addEventListener(keyup, (event) = >{
let keyCode = event.keyCode;
key_pressed[keyCode] && (key_pressed[keyCode].status = false);
event.stopPropagation();
},
true);
从上面代码可以看出我在 key_pressed 变数中记录对应按键以及按键对应的 action 动作,在 keydown 与 keyup 的时候对应修改当前 key 的 status 的状态值,所以可以在 Interval 中根据 key_pressed 这个变数的 status 值执行对应的 action 动作,以下为执行流程图:
HT 的轻量化,自适应让当前系统在手机端也能流畅的运行,当然目前移动端与电脑端的 2D 图纸部分是载入不同的图纸,在移动端的 2D 部分只留下操作挖机的操作部分,其它部分进行了相应的舍弃,不然在移动端小屏幕下无法展示如此多的数据,在 3D 场景部分都是共用同一个场景,通过场景搭建部分的批量操作使得 3D 在手机端也十分流畅的运行,以下为手机端运行截图:
总结
物联网已经融入了现代生活,通过内嵌到机械设备中的电子设备,我们能够完成对机械设备的运转、性能的监控,以及对机械设备出现的问题进行及时的预警。在该系统 2D 面板监控部分就是对采集过来的数据进行可视化的展示,而且我们可以借助大数据和物联网技术,将一台台机械通过机载控制器、感测器和无线通讯模块,与一个庞大的网路连接,每挥动一铲、行动一步,都形成数据痕迹。大数据精准描绘出基础建设开工率等情况,成为观察固定资产投资等经济变化的风向标。所以在实现上述挖机动作之后,通过与挖机感测器进行连接之后,可以将挖掘机此时的真实动作通过数据传递到系统,系统则会根据动作进行相应的真实操作,真正实现了挖机与网路的互联互通。
程序运行截图:
推荐阅读: