@operato/scene-urdf 7.3.9 → 7.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/CHANGELOG.md +0 -352
- package/demo/index.html +0 -109
- package/src/editors/index.ts +0 -0
- package/src/elements/drag-n-drop.ts +0 -142
- package/src/elements/urdf-controller-element.ts +0 -297
- package/src/elements/urdf-drag-controls.ts +0 -248
- package/src/elements/urdf-manipulator-element.ts +0 -133
- package/src/elements/urdf-viewer-element.ts +0 -496
- package/src/index.ts +0 -2
- package/src/templates/index.ts +0 -4
- package/src/templates/urdf-controller.ts +0 -16
- package/src/templates/urdf-viewer.ts +0 -16
- package/src/urdf-controller.ts +0 -82
- package/src/urdf-viewer.ts +0 -249
- package/tsconfig.json +0 -24
- package/tsconfig.tsbuildinfo +0 -1
- package/web-dev-server.config.mjs +0 -27
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
import { LitElement, css, html, PropertyValues } from 'lit'
|
|
2
|
-
import { customElement, property } from 'lit/decorators.js'
|
|
3
|
-
import * as THREE from 'three'
|
|
4
|
-
import { registerDragEvents } from './drag-n-drop'
|
|
5
|
-
import { ScrollbarStyles } from '@operato/styles'
|
|
6
|
-
import { URDFRobot } from 'urdf-loader'
|
|
7
|
-
import URDFManipulatorElement from './urdf-manipulator-element'
|
|
8
|
-
|
|
9
|
-
const DEG2RAD = Math.PI / 180
|
|
10
|
-
const RAD2DEG = 1 / DEG2RAD
|
|
11
|
-
|
|
12
|
-
@customElement('urdf-controller')
|
|
13
|
-
export default class URDFControllerElement extends LitElement {
|
|
14
|
-
static styles = [
|
|
15
|
-
ScrollbarStyles,
|
|
16
|
-
css`
|
|
17
|
-
:host {
|
|
18
|
-
display: flex;
|
|
19
|
-
flex-direction: column;
|
|
20
|
-
width: 100%;
|
|
21
|
-
margin: 15px 0;
|
|
22
|
-
overflow: hidden;
|
|
23
|
-
user-select: none;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
:host > * {
|
|
27
|
-
margin: 5px 0;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
input[type='number'] {
|
|
31
|
-
color: white;
|
|
32
|
-
border: none;
|
|
33
|
-
font-weight: 300;
|
|
34
|
-
background: rgba(255, 255, 255, 0.25);
|
|
35
|
-
padding: 1px 2px;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
ul {
|
|
39
|
-
list-style: none;
|
|
40
|
-
padding: 0;
|
|
41
|
-
margin: 0;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
input[type='range'] {
|
|
45
|
-
-webkit-appearance: none;
|
|
46
|
-
border: none;
|
|
47
|
-
outline: none;
|
|
48
|
-
width: 100%;
|
|
49
|
-
flex: 1;
|
|
50
|
-
height: 16px;
|
|
51
|
-
background-color: transparent;
|
|
52
|
-
}
|
|
53
|
-
input[type='range']::-webkit-slider-runnable-track {
|
|
54
|
-
width: 100%;
|
|
55
|
-
height: 1px;
|
|
56
|
-
background: white;
|
|
57
|
-
border: none;
|
|
58
|
-
border-radius: 5px;
|
|
59
|
-
}
|
|
60
|
-
input[type='range']::-webkit-slider-thumb {
|
|
61
|
-
-webkit-appearance: none;
|
|
62
|
-
border: none;
|
|
63
|
-
height: 10px;
|
|
64
|
-
width: 10px;
|
|
65
|
-
border-radius: 50%;
|
|
66
|
-
background: white;
|
|
67
|
-
margin-top: -5px;
|
|
68
|
-
}
|
|
69
|
-
input[type='range']:focus {
|
|
70
|
-
outline: none;
|
|
71
|
-
}
|
|
72
|
-
input[type='range']:focus::-webkit-slider-runnable-track {
|
|
73
|
-
background: white;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
input[type='range']::-moz-range-track {
|
|
77
|
-
width: 100%;
|
|
78
|
-
height: 1px;
|
|
79
|
-
background: white;
|
|
80
|
-
border: none;
|
|
81
|
-
border-radius: 5px;
|
|
82
|
-
}
|
|
83
|
-
input[type='range']::-moz-range-thumb {
|
|
84
|
-
border: none;
|
|
85
|
-
height: 10px;
|
|
86
|
-
width: 10px;
|
|
87
|
-
border-radius: 50%;
|
|
88
|
-
background: white;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
input[type='range']:-moz-focusring {
|
|
92
|
-
outline: 1px solid white;
|
|
93
|
-
outline-offset: -1px;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
input[type='range']::-ms-track {
|
|
97
|
-
width: 100%;
|
|
98
|
-
height: 1px;
|
|
99
|
-
background: white;
|
|
100
|
-
border-radius: 10px;
|
|
101
|
-
color: transparent;
|
|
102
|
-
border: none;
|
|
103
|
-
outline: none;
|
|
104
|
-
}
|
|
105
|
-
input[type='range']::-ms-thumb {
|
|
106
|
-
height: 10px;
|
|
107
|
-
width: 10px;
|
|
108
|
-
border-radius: 50%;
|
|
109
|
-
background: white;
|
|
110
|
-
border: none;
|
|
111
|
-
outline: none;
|
|
112
|
-
margin-top: 2px;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
input:focus {
|
|
116
|
-
outline: none;
|
|
117
|
-
opacity: 1;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/* list of joint sliders */
|
|
121
|
-
ul {
|
|
122
|
-
flex: 1;
|
|
123
|
-
overflow-y: auto;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
li {
|
|
127
|
-
font-size: 16px;
|
|
128
|
-
display: flex;
|
|
129
|
-
align-items: center;
|
|
130
|
-
padding: 1px 0;
|
|
131
|
-
|
|
132
|
-
width: 100%;
|
|
133
|
-
user-select: text;
|
|
134
|
-
|
|
135
|
-
transition: background 0.25s ease;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
li[robot-hovered] {
|
|
139
|
-
background: rgba(255, 255, 255, 0.35);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
li:hover {
|
|
143
|
-
background: rgba(255, 255, 255, 0.35);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
li span {
|
|
147
|
-
padding: 0 5px;
|
|
148
|
-
max-width: 125px;
|
|
149
|
-
text-overflow: ellipsis;
|
|
150
|
-
overflow: hidden;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
li input[type='number'] {
|
|
154
|
-
width: 50px;
|
|
155
|
-
overflow: hidden;
|
|
156
|
-
}
|
|
157
|
-
`
|
|
158
|
-
]
|
|
159
|
-
|
|
160
|
-
@property({ type: Object }) viewer?: URDFManipulatorElement
|
|
161
|
-
@property({ type: Object }) robot?: URDFRobot
|
|
162
|
-
|
|
163
|
-
render() {
|
|
164
|
-
const { joints = {} } = this.robot || {}
|
|
165
|
-
const { ignoreLimits = false } = this.viewer || {}
|
|
166
|
-
const jointsArray = Object.values(joints)
|
|
167
|
-
|
|
168
|
-
return html`
|
|
169
|
-
<ul>
|
|
170
|
-
${jointsArray.map(joint => {
|
|
171
|
-
var { jointType, name, angle, limit } = joint
|
|
172
|
-
var degVal: number | string = Number(angle || 0)
|
|
173
|
-
|
|
174
|
-
if (jointType === 'revolute' || jointType === 'continuous') {
|
|
175
|
-
degVal *= RAD2DEG
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (Math.abs(degVal) > 1) {
|
|
179
|
-
degVal = degVal.toFixed(1)
|
|
180
|
-
} else {
|
|
181
|
-
degVal = degVal.toPrecision(2)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
var sliderMin
|
|
185
|
-
var sliderMax
|
|
186
|
-
var inputMin
|
|
187
|
-
var inputMax
|
|
188
|
-
|
|
189
|
-
if (ignoreLimits || jointType === 'continuous') {
|
|
190
|
-
sliderMin = -6.28
|
|
191
|
-
sliderMax = 6.28
|
|
192
|
-
|
|
193
|
-
inputMin = -6.28 * RAD2DEG
|
|
194
|
-
inputMax = 6.28 * RAD2DEG
|
|
195
|
-
} else {
|
|
196
|
-
sliderMin = limit.lower
|
|
197
|
-
sliderMax = limit.upper
|
|
198
|
-
|
|
199
|
-
inputMin = Number(limit.lower) * RAD2DEG
|
|
200
|
-
inputMax = Number(limit.upper) * RAD2DEG
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return html`
|
|
204
|
-
<li joint-type=${jointType} joint-name=${name}>
|
|
205
|
-
<span title=${name}>${name}</span>
|
|
206
|
-
<input
|
|
207
|
-
type="range"
|
|
208
|
-
.value=${String(angle)}
|
|
209
|
-
step="0.0001"
|
|
210
|
-
min=${sliderMin}
|
|
211
|
-
max=${sliderMax}
|
|
212
|
-
@input=${(e: Event) => {
|
|
213
|
-
this.viewer?.setJointValue(name, (e.target as any).value)
|
|
214
|
-
}}
|
|
215
|
-
/>
|
|
216
|
-
<input
|
|
217
|
-
type="number"
|
|
218
|
-
.value=${degVal}
|
|
219
|
-
step="0.0001"
|
|
220
|
-
min=${inputMin}
|
|
221
|
-
max=${inputMax}
|
|
222
|
-
@change=${(e: Event) => {
|
|
223
|
-
this.viewer?.setJointValue(name, Number((e.target as HTMLInputElement).value) * DEG2RAD)
|
|
224
|
-
}}
|
|
225
|
-
/>
|
|
226
|
-
</li>
|
|
227
|
-
`
|
|
228
|
-
})}
|
|
229
|
-
</ul>
|
|
230
|
-
`
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
updated(changes: PropertyValues<this>) {
|
|
234
|
-
if (changes.has('viewer')) {
|
|
235
|
-
this._setupViewer(this.viewer)
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
_setupViewer(viewer?: URDFManipulatorElement) {
|
|
240
|
-
if (!viewer) {
|
|
241
|
-
return
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
this.robot = viewer.robot
|
|
245
|
-
|
|
246
|
-
viewer.addEventListener('urdf-processed', () => {
|
|
247
|
-
this.robot = viewer.robot
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
viewer.addEventListener('ignore-limits-change', () => {
|
|
251
|
-
this.requestUpdate()
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
viewer.addEventListener('angle-change', (e: Event) => {
|
|
255
|
-
this.requestUpdate()
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
viewer.addEventListener('joint-mouseover', (e: Event) => {
|
|
259
|
-
const j = this.renderRoot.querySelector(`li[joint-name="${(e as CustomEvent).detail}"]`)
|
|
260
|
-
if (j) {
|
|
261
|
-
j.setAttribute('robot-hovered', 'true')
|
|
262
|
-
}
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
viewer.addEventListener('joint-mouseout', (e: Event) => {
|
|
266
|
-
const j = this.renderRoot.querySelector(`li[joint-name="${(e as CustomEvent).detail}"]`)
|
|
267
|
-
if (j) {
|
|
268
|
-
j.removeAttribute('robot-hovered')
|
|
269
|
-
}
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
let originalNoAutoRecenter: boolean
|
|
273
|
-
viewer.addEventListener('manipulate-start', (e: Event) => {
|
|
274
|
-
const j = this.renderRoot.querySelector(`li[joint-name="${(e as CustomEvent).detail}"]`)
|
|
275
|
-
if (j) {
|
|
276
|
-
// ??
|
|
277
|
-
j.scrollIntoView({ block: 'nearest' })
|
|
278
|
-
window.scrollTo(0, 0)
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
originalNoAutoRecenter = viewer.noAutoRecenter
|
|
282
|
-
viewer.noAutoRecenter = true
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
viewer.addEventListener('manipulate-end', (e: Event) => {
|
|
286
|
-
viewer.noAutoRecenter = originalNoAutoRecenter
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
registerDragEvents(viewer, () => {
|
|
290
|
-
this.setColor('#263238')
|
|
291
|
-
})
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
setColor(color: string) {
|
|
295
|
-
this.viewer!.highlightColor = '#' + new THREE.Color(0xffffff).lerp(new THREE.Color(color), 0.35).getHexString()
|
|
296
|
-
}
|
|
297
|
-
}
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import { Raycaster, Vector3, Plane, Vector2, Scene, Camera, Object3D, Ray } from 'three'
|
|
2
|
-
import { URDFJoint } from 'urdf-loader'
|
|
3
|
-
|
|
4
|
-
// Find the nearest parent that is a joint
|
|
5
|
-
function isJoint(j: URDFJoint) {
|
|
6
|
-
return j.isURDFJoint && j.jointType !== 'fixed'
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function findNearestJoint(child: Object3D) {
|
|
10
|
-
let curr: Object3D | null = child
|
|
11
|
-
while (curr) {
|
|
12
|
-
if (isJoint(curr as URDFJoint)) {
|
|
13
|
-
return curr
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
curr = curr.parent
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return curr
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const prevHitPoint = new Vector3()
|
|
23
|
-
const newHitPoint = new Vector3()
|
|
24
|
-
const pivotPoint = new Vector3()
|
|
25
|
-
const tempVector = new Vector3()
|
|
26
|
-
const tempVector2 = new Vector3()
|
|
27
|
-
const projectedStartPoint = new Vector3()
|
|
28
|
-
const projectedEndPoint = new Vector3()
|
|
29
|
-
const plane = new Plane()
|
|
30
|
-
export class URDFDragControls {
|
|
31
|
-
scene: Scene
|
|
32
|
-
|
|
33
|
-
enabled: boolean
|
|
34
|
-
raycaster: Raycaster
|
|
35
|
-
initialGrabPoint: Vector3
|
|
36
|
-
hitDistance: number
|
|
37
|
-
|
|
38
|
-
hovered: any
|
|
39
|
-
manipulating: any
|
|
40
|
-
|
|
41
|
-
constructor(scene: Scene) {
|
|
42
|
-
this.enabled = true
|
|
43
|
-
this.scene = scene
|
|
44
|
-
|
|
45
|
-
this.raycaster = new Raycaster()
|
|
46
|
-
this.initialGrabPoint = new Vector3()
|
|
47
|
-
|
|
48
|
-
this.hitDistance = -1
|
|
49
|
-
this.hovered = null
|
|
50
|
-
this.manipulating = null
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
update() {
|
|
54
|
-
const { raycaster, hovered, manipulating, scene } = this
|
|
55
|
-
|
|
56
|
-
if (manipulating) {
|
|
57
|
-
return
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let hoveredJoint = null
|
|
61
|
-
const intersections = raycaster.intersectObject(scene, true)
|
|
62
|
-
if (intersections.length !== 0) {
|
|
63
|
-
const hit = intersections[0]
|
|
64
|
-
this.hitDistance = hit.distance
|
|
65
|
-
hoveredJoint = findNearestJoint(hit.object)
|
|
66
|
-
this.initialGrabPoint.copy(hit.point)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (hoveredJoint !== hovered) {
|
|
70
|
-
if (hovered) {
|
|
71
|
-
this.onUnhover(hovered)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
this.hovered = hoveredJoint
|
|
75
|
-
|
|
76
|
-
if (hoveredJoint) {
|
|
77
|
-
this.onHover(hoveredJoint as URDFJoint)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
updateJoint(joint: URDFJoint, angle: number) {
|
|
83
|
-
joint.setJointValue(angle)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
onDragStart(joint: URDFJoint) {}
|
|
87
|
-
|
|
88
|
-
onDragEnd(joint: URDFJoint) {}
|
|
89
|
-
|
|
90
|
-
onHover(joint: URDFJoint) {}
|
|
91
|
-
|
|
92
|
-
onUnhover(joint: URDFJoint) {}
|
|
93
|
-
|
|
94
|
-
getRevoluteDelta(joint: URDFJoint, startPoint: Vector3, endPoint: Vector3) {
|
|
95
|
-
// set up the plane
|
|
96
|
-
tempVector.copy(joint.axis).transformDirection(joint.matrixWorld).normalize()
|
|
97
|
-
pivotPoint.set(0, 0, 0).applyMatrix4(joint.matrixWorld)
|
|
98
|
-
plane.setFromNormalAndCoplanarPoint(tempVector, pivotPoint)
|
|
99
|
-
|
|
100
|
-
// project the drag points onto the plane
|
|
101
|
-
plane.projectPoint(startPoint, projectedStartPoint)
|
|
102
|
-
plane.projectPoint(endPoint, projectedEndPoint)
|
|
103
|
-
|
|
104
|
-
// get the directions relative to the pivot
|
|
105
|
-
projectedStartPoint.sub(pivotPoint)
|
|
106
|
-
projectedEndPoint.sub(pivotPoint)
|
|
107
|
-
|
|
108
|
-
tempVector.crossVectors(projectedStartPoint, projectedEndPoint)
|
|
109
|
-
|
|
110
|
-
const direction = Math.sign(tempVector.dot(plane.normal))
|
|
111
|
-
return direction * projectedEndPoint.angleTo(projectedStartPoint)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
getPrismaticDelta(joint: URDFJoint, startPoint: Vector3, endPoint: Vector3) {
|
|
115
|
-
tempVector.subVectors(endPoint, startPoint)
|
|
116
|
-
plane.normal.copy(joint.axis).transformDirection(joint.parent!.matrixWorld).normalize()
|
|
117
|
-
|
|
118
|
-
return tempVector.dot(plane.normal)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
moveRay(toRay: Ray) {
|
|
122
|
-
const { raycaster, hitDistance, manipulating } = this
|
|
123
|
-
const { ray } = raycaster
|
|
124
|
-
|
|
125
|
-
if (manipulating) {
|
|
126
|
-
ray.at(hitDistance, prevHitPoint)
|
|
127
|
-
toRay.at(hitDistance, newHitPoint)
|
|
128
|
-
|
|
129
|
-
let delta = 0
|
|
130
|
-
if (manipulating.jointType === 'revolute' || manipulating.jointType === 'continuous') {
|
|
131
|
-
delta = this.getRevoluteDelta(manipulating, prevHitPoint, newHitPoint)
|
|
132
|
-
} else if (manipulating.jointType === 'prismatic') {
|
|
133
|
-
delta = this.getPrismaticDelta(manipulating, prevHitPoint, newHitPoint)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (delta) {
|
|
137
|
-
this.updateJoint(manipulating, manipulating.angle + delta)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
this.raycaster.ray.copy(toRay)
|
|
142
|
-
this.update()
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
setGrabbed(grabbed: boolean) {
|
|
146
|
-
const { hovered, manipulating } = this
|
|
147
|
-
if (grabbed) {
|
|
148
|
-
if (manipulating !== null || hovered === null) {
|
|
149
|
-
return
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
this.manipulating = hovered
|
|
153
|
-
this.onDragStart(hovered)
|
|
154
|
-
} else {
|
|
155
|
-
if (this.manipulating === null) {
|
|
156
|
-
return
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
this.onDragEnd(this.manipulating)
|
|
160
|
-
this.manipulating = null
|
|
161
|
-
this.update()
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export class PointerURDFDragControls extends URDFDragControls {
|
|
167
|
-
camera: Camera
|
|
168
|
-
domElement: HTMLElement
|
|
169
|
-
|
|
170
|
-
_mouseDown: (e: MouseEvent) => void
|
|
171
|
-
_mouseMove: (e: MouseEvent) => void
|
|
172
|
-
_mouseUp: (e: MouseEvent) => void
|
|
173
|
-
|
|
174
|
-
constructor(scene: Scene, camera: Camera, domElement: HTMLElement) {
|
|
175
|
-
super(scene)
|
|
176
|
-
|
|
177
|
-
this.camera = camera
|
|
178
|
-
this.domElement = domElement
|
|
179
|
-
|
|
180
|
-
const raycaster = new Raycaster()
|
|
181
|
-
const mouse = new Vector2()
|
|
182
|
-
|
|
183
|
-
function updateMouse(e: MouseEvent) {
|
|
184
|
-
mouse.x = (e.offsetX / domElement.offsetWidth) * 2 - 1
|
|
185
|
-
mouse.y = -(e.offsetY / domElement.offsetHeight) * 2 + 1
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
this._mouseDown = (e: MouseEvent) => {
|
|
189
|
-
updateMouse(e)
|
|
190
|
-
raycaster.setFromCamera(mouse, this.camera)
|
|
191
|
-
this.moveRay(raycaster.ray)
|
|
192
|
-
this.setGrabbed(true)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
this._mouseMove = (e: MouseEvent) => {
|
|
196
|
-
updateMouse(e)
|
|
197
|
-
raycaster.setFromCamera(mouse, this.camera)
|
|
198
|
-
this.moveRay(raycaster.ray)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
this._mouseUp = (e: MouseEvent) => {
|
|
202
|
-
updateMouse(e)
|
|
203
|
-
raycaster.setFromCamera(mouse, this.camera)
|
|
204
|
-
this.moveRay(raycaster.ray)
|
|
205
|
-
this.setGrabbed(false)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
domElement.addEventListener('pointerdown', this._mouseDown)
|
|
209
|
-
domElement.addEventListener('pointermove', this._mouseMove)
|
|
210
|
-
domElement.addEventListener('pointerup', this._mouseUp)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
getRevoluteDelta(joint: URDFJoint, startPoint: Vector3, endPoint: Vector3) {
|
|
214
|
-
const { camera, initialGrabPoint } = this
|
|
215
|
-
|
|
216
|
-
// set up the plane
|
|
217
|
-
tempVector.copy(joint.axis).transformDirection(joint.matrixWorld).normalize()
|
|
218
|
-
pivotPoint.set(0, 0, 0).applyMatrix4(joint.matrixWorld)
|
|
219
|
-
plane.setFromNormalAndCoplanarPoint(tempVector, pivotPoint)
|
|
220
|
-
|
|
221
|
-
tempVector.copy(camera.position).sub(initialGrabPoint).normalize()
|
|
222
|
-
|
|
223
|
-
// if looking into the plane of rotation
|
|
224
|
-
if (Math.abs(tempVector.dot(plane.normal)) > 0.3) {
|
|
225
|
-
return super.getRevoluteDelta(joint, startPoint, endPoint)
|
|
226
|
-
} else {
|
|
227
|
-
// get the up direction
|
|
228
|
-
tempVector.set(0, 1, 0).transformDirection(camera.matrixWorld)
|
|
229
|
-
|
|
230
|
-
// get points projected onto the plane of rotation
|
|
231
|
-
plane.projectPoint(startPoint, projectedStartPoint)
|
|
232
|
-
plane.projectPoint(endPoint, projectedEndPoint)
|
|
233
|
-
|
|
234
|
-
tempVector.set(0, 0, -1).transformDirection(camera.matrixWorld)
|
|
235
|
-
tempVector.cross(plane.normal)
|
|
236
|
-
tempVector2.subVectors(endPoint, startPoint)
|
|
237
|
-
|
|
238
|
-
return tempVector.dot(tempVector2)
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
dispose() {
|
|
243
|
-
const { domElement } = this
|
|
244
|
-
domElement.removeEventListener('pointerdown', this._mouseDown)
|
|
245
|
-
domElement.removeEventListener('pointermove', this._mouseMove)
|
|
246
|
-
domElement.removeEventListener('pointerup', this._mouseUp)
|
|
247
|
-
}
|
|
248
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { customElement } from 'lit/decorators.js'
|
|
2
|
-
import * as THREE from 'three'
|
|
3
|
-
import { PointerURDFDragControls } from './urdf-drag-controls'
|
|
4
|
-
import { Material, MeshPhongMaterial } from 'three'
|
|
5
|
-
import URDFViewerElement from './urdf-viewer-element'
|
|
6
|
-
import { URDFJoint } from 'urdf-loader'
|
|
7
|
-
|
|
8
|
-
// urdf-manipulator element
|
|
9
|
-
// Displays a URDF model that can be manipulated with the mouse
|
|
10
|
-
|
|
11
|
-
// Events
|
|
12
|
-
// joint-mouseover: Fired when a joint is hovered over
|
|
13
|
-
// joint-mouseout: Fired when a joint is no longer hovered over
|
|
14
|
-
// manipulate-start: Fires when a joint is manipulated
|
|
15
|
-
// manipulate-end: Fires when a joint is done being manipulated
|
|
16
|
-
|
|
17
|
-
@customElement('urdf-viewer')
|
|
18
|
-
export default class URDFManipulatorElement extends URDFViewerElement {
|
|
19
|
-
static get observedAttributes() {
|
|
20
|
-
return ['highlight-color', ...super.observedAttributes]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
highlightMaterial: MeshPhongMaterial
|
|
24
|
-
dragControls: PointerURDFDragControls
|
|
25
|
-
|
|
26
|
-
get disableDragging() {
|
|
27
|
-
return this.hasAttribute('disable-dragging')
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
set disableDragging(val) {
|
|
31
|
-
val ? this.setAttribute('disable-dragging', String(!!val)) : this.removeAttribute('disable-dragging')
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
get highlightColor() {
|
|
35
|
-
return this.getAttribute('highlight-color') || '#FFFFFF'
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
set highlightColor(val) {
|
|
39
|
-
val ? this.setAttribute('highlight-color', val) : this.removeAttribute('highlight-color')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
constructor() {
|
|
43
|
-
super()
|
|
44
|
-
|
|
45
|
-
// The highlight material
|
|
46
|
-
this.highlightMaterial = new THREE.MeshPhongMaterial({
|
|
47
|
-
shininess: 10,
|
|
48
|
-
color: this.highlightColor,
|
|
49
|
-
emissive: this.highlightColor,
|
|
50
|
-
emissiveIntensity: 0.25
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
const isJoint = (j: URDFJoint) => {
|
|
54
|
-
return j.isURDFJoint && j.jointType !== 'fixed'
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Highlight the link geometry under a joint
|
|
58
|
-
const highlightLinkGeometry = (m: THREE.Material, revert: boolean) => {
|
|
59
|
-
const traverse = (c: any) => {
|
|
60
|
-
// Set or revert the highlight color
|
|
61
|
-
if (c.type === 'Mesh') {
|
|
62
|
-
if (revert) {
|
|
63
|
-
c.material = c.__origMaterial
|
|
64
|
-
delete c.__origMaterial
|
|
65
|
-
} else {
|
|
66
|
-
c.__origMaterial = c.material
|
|
67
|
-
c.material = this.highlightMaterial
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Look into the children and stop if the next child is
|
|
72
|
-
// another joint
|
|
73
|
-
if (c === m || !isJoint(c)) {
|
|
74
|
-
for (let i = 0; i < c.children.length; i++) {
|
|
75
|
-
traverse(c.children[i])
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
traverse(m)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const el = this.renderer.domElement
|
|
84
|
-
|
|
85
|
-
const dragControls = new PointerURDFDragControls(this.scene, this.camera, el)
|
|
86
|
-
|
|
87
|
-
dragControls.onDragStart = joint => {
|
|
88
|
-
this.dispatchEvent(new CustomEvent('manipulate-start', { bubbles: true, cancelable: true, detail: joint.name }))
|
|
89
|
-
this.controls.enabled = false
|
|
90
|
-
this.redraw()
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
dragControls.onDragEnd = joint => {
|
|
94
|
-
this.dispatchEvent(new CustomEvent('manipulate-end', { bubbles: true, cancelable: true, detail: joint.name }))
|
|
95
|
-
this.controls.enabled = true
|
|
96
|
-
this.redraw()
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
dragControls.updateJoint = (joint, angle) => {
|
|
100
|
-
this.setJointValue(joint.name, angle)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
dragControls.onHover = (joint: URDFJoint) => {
|
|
104
|
-
highlightLinkGeometry(joint as any, false)
|
|
105
|
-
this.dispatchEvent(new CustomEvent('joint-mouseover', { bubbles: true, cancelable: true, detail: joint.name }))
|
|
106
|
-
this.redraw()
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
dragControls.onUnhover = joint => {
|
|
110
|
-
highlightLinkGeometry(joint as any, true)
|
|
111
|
-
this.dispatchEvent(new CustomEvent('joint-mouseout', { bubbles: true, cancelable: true, detail: joint.name }))
|
|
112
|
-
this.redraw()
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
this.dragControls = dragControls
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
disconnectedCallback() {
|
|
119
|
-
super.disconnectedCallback()
|
|
120
|
-
this.dragControls.dispose()
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
attributeChangedCallback(attr: string, oldval: any, newval: any) {
|
|
124
|
-
super.attributeChangedCallback(attr, oldval, newval)
|
|
125
|
-
|
|
126
|
-
switch (attr) {
|
|
127
|
-
case 'highlight-color':
|
|
128
|
-
this.highlightMaterial.color.set(this.highlightColor)
|
|
129
|
-
this.highlightMaterial.emissive.set(this.highlightColor)
|
|
130
|
-
break
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|