@operato/scene-urdf 10.0.0-beta.1 → 10.0.0-beta.18
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/dist/editors/index.d.ts +6 -0
- package/dist/editors/index.js +7 -1
- package/dist/editors/index.js.map +1 -1
- package/dist/editors/property-editor-urdf-joints.d.ts +54 -0
- package/dist/editors/property-editor-urdf-joints.js +242 -0
- package/dist/editors/property-editor-urdf-joints.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/real-object-urdf.d.ts +75 -0
- package/dist/real-object-urdf.js +284 -0
- package/dist/real-object-urdf.js.map +1 -0
- package/dist/templates/index.d.ts +3 -0
- package/dist/templates/index.js +2 -3
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/{urdf-controller.d.ts → urdf.d.ts} +3 -0
- package/dist/templates/urdf.js +19 -0
- package/dist/templates/urdf.js.map +1 -0
- package/dist/urdf-object.d.ts +264 -0
- package/dist/urdf-object.js +163 -0
- package/dist/urdf-object.js.map +1 -0
- package/icons/urdf.png +0 -0
- package/package.json +5 -4
- package/dist/elements/drag-n-drop.d.ts +0 -2
- package/dist/elements/drag-n-drop.js +0 -126
- package/dist/elements/drag-n-drop.js.map +0 -1
- package/dist/elements/urdf-controller-element.d.ts +0 -12
- package/dist/elements/urdf-controller-element.js +0 -283
- package/dist/elements/urdf-controller-element.js.map +0 -1
- package/dist/elements/urdf-drag-controls.d.ts +0 -32
- package/dist/elements/urdf-drag-controls.js +0 -197
- package/dist/elements/urdf-drag-controls.js.map +0 -1
- package/dist/elements/urdf-manipulator-element.d.ts +0 -15
- package/dist/elements/urdf-manipulator-element.js +0 -112
- package/dist/elements/urdf-manipulator-element.js.map +0 -1
- package/dist/elements/urdf-viewer-element.d.ts +0 -53
- package/dist/elements/urdf-viewer-element.js +0 -414
- package/dist/elements/urdf-viewer-element.js.map +0 -1
- package/dist/templates/urdf-controller.js +0 -16
- package/dist/templates/urdf-controller.js.map +0 -1
- package/dist/templates/urdf-viewer.d.ts +0 -14
- package/dist/templates/urdf-viewer.js +0 -16
- package/dist/templates/urdf-viewer.js.map +0 -1
- package/dist/urdf-controller.d.ts +0 -15
- package/dist/urdf-controller.js +0 -70
- package/dist/urdf-controller.js.map +0 -1
- package/dist/urdf-viewer.d.ts +0 -16
- package/dist/urdf-viewer.js +0 -202
- package/dist/urdf-viewer.js.map +0 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* URDF 로봇을 things-scene 3D 공간에 네이티브로 임베드한다.
|
|
5
|
+
* GLTFObject와 대칭적인 구조 — 2D 탑뷰는 스냅샷 렌더로 표현한다.
|
|
6
|
+
*/
|
|
7
|
+
import { __decorate } from "tslib";
|
|
8
|
+
import { RectPath, Shape, sceneComponent } from '@hatiolab/things-scene';
|
|
9
|
+
import { RealObjectURDF } from './real-object-urdf.js';
|
|
10
|
+
const BASE_URL_ALIAS = '$base_url';
|
|
11
|
+
const NATURE = {
|
|
12
|
+
mutable: false,
|
|
13
|
+
resizable: true,
|
|
14
|
+
rotatable: true,
|
|
15
|
+
properties: [
|
|
16
|
+
{
|
|
17
|
+
type: 'string',
|
|
18
|
+
label: 'url',
|
|
19
|
+
name: 'src',
|
|
20
|
+
property: {
|
|
21
|
+
displayField: 'id',
|
|
22
|
+
displayFullUrl: true,
|
|
23
|
+
baseUrlAlias: BASE_URL_ALIAS,
|
|
24
|
+
defaultStorage: '3d-model',
|
|
25
|
+
storageFilters: {
|
|
26
|
+
type: Array,
|
|
27
|
+
value: [
|
|
28
|
+
{
|
|
29
|
+
name: 'category',
|
|
30
|
+
value: 'urdf'
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
useUpload: true,
|
|
35
|
+
category: 'application'
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: 'select',
|
|
40
|
+
label: 'up-axis',
|
|
41
|
+
name: 'upAxis',
|
|
42
|
+
property: {
|
|
43
|
+
options: [
|
|
44
|
+
{ display: 'Z (URDF default)', value: 'z' },
|
|
45
|
+
{ display: 'Y (Three.js default)', value: 'y' }
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: 'number',
|
|
51
|
+
label: 'unit-scale',
|
|
52
|
+
name: 'unitScale',
|
|
53
|
+
placeholder: '1000'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
type: 'urdf-joints',
|
|
57
|
+
label: '',
|
|
58
|
+
name: 'joints',
|
|
59
|
+
editor: {
|
|
60
|
+
fullwidth: true
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
'value-property': 'source',
|
|
65
|
+
help: 'scene/component/urdf'
|
|
66
|
+
};
|
|
67
|
+
let URDFObject = class URDFObject extends RectPath(Shape) {
|
|
68
|
+
get hasTextProperty() {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
is3dish() {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
get controls() {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
render(context) {
|
|
78
|
+
const { left, top, width, height } = this.bounds;
|
|
79
|
+
context.beginPath();
|
|
80
|
+
const snapshot = this._topViewSnapshot;
|
|
81
|
+
if (snapshot) {
|
|
82
|
+
context.drawImage(snapshot, left, top, width, height);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// 폴백: 로봇 아이콘 박스 + 중앙 라벨
|
|
86
|
+
context.rect(left, top, width, height);
|
|
87
|
+
context.fillStyle = '#e3f2fd';
|
|
88
|
+
context.fill();
|
|
89
|
+
context.strokeStyle = '#1976d2';
|
|
90
|
+
context.lineWidth = 1;
|
|
91
|
+
context.stroke();
|
|
92
|
+
const src = this.getState('src');
|
|
93
|
+
const label = src ? src.split('/').pop()?.replace(/\.[^.]+$/, '') || 'URDF' : 'URDF';
|
|
94
|
+
const fontSize = Math.max(10, Math.min(width, height) * 0.12);
|
|
95
|
+
context.fillStyle = '#1976d2';
|
|
96
|
+
context.font = `${fontSize}px sans-serif`;
|
|
97
|
+
context.textAlign = 'center';
|
|
98
|
+
context.textBaseline = 'middle';
|
|
99
|
+
context.fillText(label, left + width / 2, top + height / 2, width * 0.9);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async ready() {
|
|
103
|
+
await super.ready();
|
|
104
|
+
this._ensureTopViewSnapshot();
|
|
105
|
+
}
|
|
106
|
+
onchange(after, before) {
|
|
107
|
+
super.onchange(after, before);
|
|
108
|
+
if ('src' in after) {
|
|
109
|
+
this._topViewSnapshot = undefined;
|
|
110
|
+
this._ensureTopViewSnapshot();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
_ensureTopViewSnapshot() {
|
|
114
|
+
const src = this.getState('src');
|
|
115
|
+
if (!src)
|
|
116
|
+
return;
|
|
117
|
+
const cached = RealObjectURDF.getTopViewCache(src);
|
|
118
|
+
if (cached) {
|
|
119
|
+
this._topViewSnapshot = cached;
|
|
120
|
+
this.invalidate();
|
|
121
|
+
}
|
|
122
|
+
// 캐시 miss인 경우 3D 씬이 활성화되면 _onLoaded에서 자동 생성한다.
|
|
123
|
+
}
|
|
124
|
+
buildRealObject() {
|
|
125
|
+
return new RealObjectURDF(this);
|
|
126
|
+
}
|
|
127
|
+
get nature() {
|
|
128
|
+
return NATURE;
|
|
129
|
+
}
|
|
130
|
+
get source() {
|
|
131
|
+
return this.getState('src');
|
|
132
|
+
}
|
|
133
|
+
set source(source) {
|
|
134
|
+
this.setState('src', source);
|
|
135
|
+
}
|
|
136
|
+
set dimension(dimension) {
|
|
137
|
+
const { width = 1, height = 1, depth = 1 } = dimension;
|
|
138
|
+
this.setState({ width, height, depth });
|
|
139
|
+
this.realObject?.updateDimension();
|
|
140
|
+
}
|
|
141
|
+
// --- URDF 바인딩 API ---
|
|
142
|
+
/** 조인트 상태 맵. 값은 숫자(라디안/거리) 또는 { value } 형식 허용. */
|
|
143
|
+
get joints() {
|
|
144
|
+
return this.getState('joints');
|
|
145
|
+
}
|
|
146
|
+
set joints(value) {
|
|
147
|
+
this.setState('joints', value);
|
|
148
|
+
}
|
|
149
|
+
/** 로드된 URDF의 조인트 메타 정보. property editor가 슬라이더 UI 생성에 사용. */
|
|
150
|
+
get jointMeta() {
|
|
151
|
+
const ro = this.realObject;
|
|
152
|
+
return ro?.jointMeta ?? [];
|
|
153
|
+
}
|
|
154
|
+
get jointNames() {
|
|
155
|
+
const ro = this.realObject;
|
|
156
|
+
return ro?.jointNames ?? [];
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
URDFObject = __decorate([
|
|
160
|
+
sceneComponent('urdf')
|
|
161
|
+
], URDFObject);
|
|
162
|
+
export { URDFObject };
|
|
163
|
+
//# sourceMappingURL=urdf-object.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urdf-object.js","sourceRoot":"","sources":["../src/urdf-object.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * URDF 로봇을 things-scene 3D 공간에 네이티브로 임베드한다.\n * GLTFObject와 대칭적인 구조 — 2D 탑뷰는 스냅샷 렌더로 표현한다.\n */\n\nimport {\n RectPath,\n Shape,\n sceneComponent,\n type ComponentNature,\n type Control,\n type IRealObject\n} from '@hatiolab/things-scene'\nimport { RealObjectURDF } from './real-object-urdf.js'\nimport type { URDFJointState, URDFJointMeta } from './real-object-urdf.js'\n\nconst BASE_URL_ALIAS = '$base_url'\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'string',\n label: 'url',\n name: 'src',\n property: {\n displayField: 'id',\n displayFullUrl: true,\n baseUrlAlias: BASE_URL_ALIAS,\n defaultStorage: '3d-model',\n storageFilters: {\n type: Array,\n value: [\n {\n name: 'category',\n value: 'urdf'\n }\n ]\n },\n useUpload: true,\n category: 'application'\n }\n },\n {\n type: 'select',\n label: 'up-axis',\n name: 'upAxis',\n property: {\n options: [\n { display: 'Z (URDF default)', value: 'z' },\n { display: 'Y (Three.js default)', value: 'y' }\n ]\n }\n },\n {\n type: 'number',\n label: 'unit-scale',\n name: 'unitScale',\n placeholder: '1000'\n },\n {\n type: 'urdf-joints',\n label: '',\n name: 'joints',\n editor: {\n fullwidth: true\n }\n }\n ],\n 'value-property': 'source',\n help: 'scene/component/urdf'\n}\n\n@sceneComponent('urdf')\nexport class URDFObject extends RectPath(Shape) {\n get hasTextProperty() {\n return false\n }\n\n is3dish() {\n return true\n }\n\n get controls(): Array<Control> | undefined {\n return []\n }\n\n render(context: CanvasRenderingContext2D) {\n const { left, top, width, height } = this.bounds\n\n context.beginPath()\n\n const snapshot = (this as any)._topViewSnapshot as HTMLCanvasElement | undefined\n if (snapshot) {\n context.drawImage(snapshot, left, top, width, height)\n } else {\n // 폴백: 로봇 아이콘 박스 + 중앙 라벨\n context.rect(left, top, width, height)\n context.fillStyle = '#e3f2fd'\n context.fill()\n context.strokeStyle = '#1976d2'\n context.lineWidth = 1\n context.stroke()\n\n const src = this.getState('src') as string | undefined\n const label = src ? src.split('/').pop()?.replace(/\\.[^.]+$/, '') || 'URDF' : 'URDF'\n const fontSize = Math.max(10, Math.min(width, height) * 0.12)\n context.fillStyle = '#1976d2'\n context.font = `${fontSize}px sans-serif`\n context.textAlign = 'center'\n context.textBaseline = 'middle'\n context.fillText(label, left + width / 2, top + height / 2, width * 0.9)\n }\n }\n\n async ready() {\n await super.ready()\n this._ensureTopViewSnapshot()\n }\n\n onchange(after: Record<string, any>, before: Record<string, any>) {\n super.onchange(after, before)\n if ('src' in after) {\n (this as any)._topViewSnapshot = undefined\n this._ensureTopViewSnapshot()\n }\n }\n\n private _ensureTopViewSnapshot() {\n const src = this.getState('src') as string | undefined\n if (!src) return\n\n const cached = RealObjectURDF.getTopViewCache(src)\n if (cached) {\n (this as any)._topViewSnapshot = cached\n this.invalidate()\n }\n // 캐시 miss인 경우 3D 씬이 활성화되면 _onLoaded에서 자동 생성한다.\n }\n\n buildRealObject(): IRealObject | undefined {\n return new RealObjectURDF(this as any)\n }\n\n get nature() {\n return NATURE\n }\n\n get source() {\n return this.getState('src')\n }\n\n set source(source) {\n this.setState('src', source)\n }\n\n set dimension(dimension: { width: number; height: number; depth: number }) {\n const { width = 1, height = 1, depth = 1 } = dimension\n this.setState({ width, height, depth })\n this.realObject?.updateDimension()\n }\n\n // --- URDF 바인딩 API ---\n\n /** 조인트 상태 맵. 값은 숫자(라디안/거리) 또는 { value } 형식 허용. */\n get joints(): Record<string, URDFJointState | number> | undefined {\n return this.getState('joints')\n }\n\n set joints(value: Record<string, URDFJointState | number> | undefined) {\n this.setState('joints', value)\n }\n\n /** 로드된 URDF의 조인트 메타 정보. property editor가 슬라이더 UI 생성에 사용. */\n get jointMeta(): URDFJointMeta[] {\n const ro = this.realObject as RealObjectURDF | undefined\n return ro?.jointMeta ?? []\n }\n\n get jointNames(): string[] {\n const ro = this.realObject as RealObjectURDF | undefined\n return ro?.jointNames ?? []\n }\n}\n"]}
|
package/icons/urdf.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@operato/scene-urdf",
|
|
3
3
|
"description": "Scene module for manipulating robot simulation through URDF format",
|
|
4
4
|
"author": "heartyoh",
|
|
5
|
-
"version": "10.0.0-beta.
|
|
5
|
+
"version": "10.0.0-beta.18",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/index.js",
|
|
@@ -29,11 +29,12 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@hatiolab/things-scene": "^10.0.0-beta.1",
|
|
32
|
+
"@operato/i18n": "^10.0.0-beta.1",
|
|
33
|
+
"@operato/property-editor": "^10.0.0-beta.1",
|
|
32
34
|
"@operato/styles": "^10.0.0-beta.1",
|
|
33
35
|
"lit": "^3.1.2",
|
|
34
36
|
"three": "^0.183.0",
|
|
35
|
-
"urdf-loader": "^0.
|
|
36
|
-
"xacro-parser": "^0.3.9"
|
|
37
|
+
"urdf-loader": "^0.12.7"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"@hatiolab/prettier-config": "^1.0.0",
|
|
@@ -65,5 +66,5 @@
|
|
|
65
66
|
"prettier --write"
|
|
66
67
|
]
|
|
67
68
|
},
|
|
68
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "5c13481300d7d45650b71f876aab8059ac8212c9"
|
|
69
70
|
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
// Converts a datatransfer structer into an object with all paths and files
|
|
2
|
-
// listed out. Returns a promise that resolves with the file structure.
|
|
3
|
-
function dataTransferToFiles(dataTransfer) {
|
|
4
|
-
if (!(dataTransfer instanceof DataTransfer)) {
|
|
5
|
-
throw new Error('Data must be of type "DataTransfer"');
|
|
6
|
-
}
|
|
7
|
-
const files = {};
|
|
8
|
-
// recurse down the webkit file structure resolving
|
|
9
|
-
// the paths to files names to store in the `files`
|
|
10
|
-
// object
|
|
11
|
-
function recurseDirectory(item) {
|
|
12
|
-
if (item.isFile) {
|
|
13
|
-
return new Promise(resolve => {
|
|
14
|
-
item.file((file) => {
|
|
15
|
-
files[item.fullPath] = file;
|
|
16
|
-
resolve();
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
const reader = item.createReader();
|
|
22
|
-
return new Promise(resolve => {
|
|
23
|
-
const promises = [];
|
|
24
|
-
// exhaustively read all the directory entries
|
|
25
|
-
function readNextEntries() {
|
|
26
|
-
reader.readEntries((et) => {
|
|
27
|
-
if (et.length === 0) {
|
|
28
|
-
Promise.all(promises).then(() => resolve());
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
et.forEach((e) => {
|
|
32
|
-
promises.push(recurseDirectory(e));
|
|
33
|
-
});
|
|
34
|
-
readNextEntries();
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
readNextEntries();
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return new Promise(resolve => {
|
|
43
|
-
// Traverse down the tree and add the files into the zip
|
|
44
|
-
// const dtitems = dataTransfer.items && [...dataTransfer.items]
|
|
45
|
-
// const dtfiles = [...dataTransfer.files]
|
|
46
|
-
var dtitems = [];
|
|
47
|
-
if (dataTransfer.items) {
|
|
48
|
-
for (let i = 0; i < dataTransfer.items.length; i++) {
|
|
49
|
-
dtitems.push(dataTransfer.items[i]);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
var dtfiles = [];
|
|
53
|
-
if (dataTransfer.files) {
|
|
54
|
-
for (let i = 0; i < dataTransfer.files.length; i++) {
|
|
55
|
-
dtfiles.push(dataTransfer.files[i]);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (dtitems.length && dtitems[0].webkitGetAsEntry) {
|
|
59
|
-
const promises = [];
|
|
60
|
-
for (let i = 0; i < dtitems.length; i++) {
|
|
61
|
-
const item = dtitems[i];
|
|
62
|
-
const entry = item.webkitGetAsEntry();
|
|
63
|
-
promises.push(recurseDirectory(entry));
|
|
64
|
-
}
|
|
65
|
-
Promise.all(promises).then(() => resolve(files));
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
// add a '/' prefix to math the file directory entry
|
|
69
|
-
// on webkit browsers
|
|
70
|
-
dtfiles.filter(f => f.size !== 0).forEach(f => (files['/' + f.name] = f));
|
|
71
|
-
resolve(files);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
export function registerDragEvents(viewer, callback) {
|
|
76
|
-
document.addEventListener('dragover', e => e.preventDefault());
|
|
77
|
-
document.addEventListener('dragenter', e => e.preventDefault());
|
|
78
|
-
document.addEventListener('drop', e => {
|
|
79
|
-
e.preventDefault();
|
|
80
|
-
// convert the files
|
|
81
|
-
dataTransferToFiles(e.dataTransfer).then((files) => {
|
|
82
|
-
// removes '..' and '.' tokens and normalizes slashes
|
|
83
|
-
const cleanFilePath = (path) => {
|
|
84
|
-
return path
|
|
85
|
-
.replace(/\\/g, '/')
|
|
86
|
-
.split(/\//g)
|
|
87
|
-
.reduce((acc, el) => {
|
|
88
|
-
if (el === '..')
|
|
89
|
-
acc.pop();
|
|
90
|
-
else if (el !== '.')
|
|
91
|
-
acc.push(el);
|
|
92
|
-
return acc;
|
|
93
|
-
}, [])
|
|
94
|
-
.join('/');
|
|
95
|
-
};
|
|
96
|
-
// set the loader url modifier to check the list
|
|
97
|
-
// of files
|
|
98
|
-
const fileNames = Object.keys(files).map(n => cleanFilePath(n));
|
|
99
|
-
viewer.urlModifierFunc = (url) => {
|
|
100
|
-
// find the matching file given the requested url
|
|
101
|
-
const cleaned = cleanFilePath(url.replace(viewer.package, ''));
|
|
102
|
-
const fileName = fileNames
|
|
103
|
-
.filter(name => {
|
|
104
|
-
// check if the end of file and url are the same
|
|
105
|
-
const len = Math.min(name.length, cleaned.length);
|
|
106
|
-
return cleaned.substr(cleaned.length - len) === name.substr(name.length - len);
|
|
107
|
-
})
|
|
108
|
-
.pop();
|
|
109
|
-
if (fileName !== undefined) {
|
|
110
|
-
// revoke the url after it's been used
|
|
111
|
-
const bloburl = URL.createObjectURL(files[fileName]);
|
|
112
|
-
requestAnimationFrame(() => URL.revokeObjectURL(bloburl));
|
|
113
|
-
return bloburl;
|
|
114
|
-
}
|
|
115
|
-
return url;
|
|
116
|
-
};
|
|
117
|
-
// set the source of the element to the most likely intended display model
|
|
118
|
-
const filesNames = Object.keys(files);
|
|
119
|
-
viewer.up = '+Z';
|
|
120
|
-
document.getElementById('up-select').value = viewer.up;
|
|
121
|
-
viewer.urdf = filesNames.filter(n => /urdf$/i.test(n)).shift();
|
|
122
|
-
});
|
|
123
|
-
callback();
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
//# sourceMappingURL=drag-n-drop.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"drag-n-drop.js","sourceRoot":"","sources":["../../src/elements/drag-n-drop.ts"],"names":[],"mappings":"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","sourcesContent":["// Converts a datatransfer structer into an object with all paths and files\n\nimport URDFViewerElement from './urdf-viewer-element.js'\n\n// listed out. Returns a promise that resolves with the file structure.\nfunction dataTransferToFiles(dataTransfer: DataTransfer) {\n if (!(dataTransfer instanceof DataTransfer)) {\n throw new Error('Data must be of type \"DataTransfer\"')\n }\n\n const files = {} as any\n\n // recurse down the webkit file structure resolving\n // the paths to files names to store in the `files`\n // object\n function recurseDirectory(item: any): Promise<void> {\n if (item.isFile) {\n return new Promise(resolve => {\n item.file((file: any) => {\n files[item.fullPath] = file\n resolve()\n })\n })\n } else {\n const reader = item.createReader()\n\n return new Promise(resolve => {\n const promises = [] as any\n\n // exhaustively read all the directory entries\n function readNextEntries() {\n reader.readEntries((et: any) => {\n if (et.length === 0) {\n Promise.all(promises).then(() => resolve())\n } else {\n et.forEach((e: any) => {\n promises.push(recurseDirectory(e))\n })\n readNextEntries()\n }\n })\n }\n\n readNextEntries()\n })\n }\n }\n\n return new Promise(resolve => {\n // Traverse down the tree and add the files into the zip\n // const dtitems = dataTransfer.items && [...dataTransfer.items]\n // const dtfiles = [...dataTransfer.files]\n var dtitems = [] as DataTransferItem[]\n if (dataTransfer.items) {\n for (let i = 0; i < dataTransfer.items.length; i++) {\n dtitems.push(dataTransfer.items[i])\n }\n }\n\n var dtfiles = [] as File[]\n if (dataTransfer.files) {\n for (let i = 0; i < dataTransfer.files.length; i++) {\n dtfiles.push(dataTransfer.files[i])\n }\n }\n\n if (dtitems.length && (dtitems[0].webkitGetAsEntry as any)) {\n const promises = []\n for (let i = 0; i < dtitems.length; i++) {\n const item = dtitems[i]\n const entry = item.webkitGetAsEntry()\n\n promises.push(recurseDirectory(entry))\n }\n Promise.all(promises).then(() => resolve(files))\n } else {\n // add a '/' prefix to math the file directory entry\n // on webkit browsers\n dtfiles.filter(f => f.size !== 0).forEach(f => (files['/' + f.name] = f))\n\n resolve(files)\n }\n })\n}\n\nexport function registerDragEvents(viewer: URDFViewerElement, callback: () => void) {\n document.addEventListener('dragover', e => e.preventDefault())\n document.addEventListener('dragenter', e => e.preventDefault())\n document.addEventListener('drop', e => {\n e.preventDefault()\n\n // convert the files\n dataTransferToFiles(e.dataTransfer!).then((files: any) => {\n // removes '..' and '.' tokens and normalizes slashes\n const cleanFilePath = (path: string) => {\n return path\n .replace(/\\\\/g, '/')\n .split(/\\//g)\n .reduce((acc, el) => {\n if (el === '..') acc.pop()\n else if (el !== '.') acc.push(el)\n return acc\n }, [] as string[])\n .join('/')\n }\n\n // set the loader url modifier to check the list\n // of files\n const fileNames = Object.keys(files).map(n => cleanFilePath(n))\n viewer.urlModifierFunc = (url: string) => {\n // find the matching file given the requested url\n const cleaned = cleanFilePath(url.replace(viewer.package, ''))\n const fileName = fileNames\n .filter(name => {\n // check if the end of file and url are the same\n const len = Math.min(name.length, cleaned.length)\n return cleaned.substr(cleaned.length - len) === name.substr(name.length - len)\n })\n .pop()\n\n if (fileName !== undefined) {\n // revoke the url after it's been used\n const bloburl = URL.createObjectURL(files[fileName])\n requestAnimationFrame(() => URL.revokeObjectURL(bloburl))\n\n return bloburl\n }\n\n return url\n }\n\n // set the source of the element to the most likely intended display model\n const filesNames = Object.keys(files)\n viewer.up = '+Z'\n ;(document.getElementById('up-select') as any)!.value = viewer.up\n\n viewer.urdf = filesNames.filter(n => /urdf$/i.test(n)).shift()!\n })\n\n callback()\n })\n}\n"]}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { LitElement, PropertyValues } from 'lit';
|
|
2
|
-
import { URDFRobot } from 'urdf-loader';
|
|
3
|
-
import URDFManipulatorElement from './urdf-manipulator-element.js';
|
|
4
|
-
export default class URDFControllerElement extends LitElement {
|
|
5
|
-
static styles: import("lit").CSSResult[];
|
|
6
|
-
viewer?: URDFManipulatorElement;
|
|
7
|
-
robot?: URDFRobot;
|
|
8
|
-
render(): import("lit-html").TemplateResult<1>;
|
|
9
|
-
updated(changes: PropertyValues<this>): void;
|
|
10
|
-
_setupViewer(viewer?: URDFManipulatorElement): void;
|
|
11
|
-
setColor(color: string): void;
|
|
12
|
-
}
|
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import { __decorate } from "tslib";
|
|
2
|
-
import { LitElement, css, html } from 'lit';
|
|
3
|
-
import { customElement, property } from 'lit/decorators.js';
|
|
4
|
-
import * as THREE from 'three';
|
|
5
|
-
import { registerDragEvents } from './drag-n-drop.js';
|
|
6
|
-
import { ScrollbarStyles } from '@operato/styles';
|
|
7
|
-
const DEG2RAD = Math.PI / 180;
|
|
8
|
-
const RAD2DEG = 1 / DEG2RAD;
|
|
9
|
-
let URDFControllerElement = class URDFControllerElement extends LitElement {
|
|
10
|
-
static styles = [
|
|
11
|
-
ScrollbarStyles,
|
|
12
|
-
css `
|
|
13
|
-
:host {
|
|
14
|
-
display: flex;
|
|
15
|
-
flex-direction: column;
|
|
16
|
-
width: 100%;
|
|
17
|
-
margin: 15px 0;
|
|
18
|
-
overflow: hidden;
|
|
19
|
-
user-select: none;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
:host > * {
|
|
23
|
-
margin: 5px 0;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
input[type='number'] {
|
|
27
|
-
color: white;
|
|
28
|
-
border: none;
|
|
29
|
-
font-weight: 300;
|
|
30
|
-
background: rgba(255, 255, 255, 0.25);
|
|
31
|
-
padding: 1px 2px;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
ul {
|
|
35
|
-
list-style: none;
|
|
36
|
-
padding: 0;
|
|
37
|
-
margin: 0;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
input[type='range'] {
|
|
41
|
-
-webkit-appearance: none;
|
|
42
|
-
border: none;
|
|
43
|
-
outline: none;
|
|
44
|
-
width: 100%;
|
|
45
|
-
flex: 1;
|
|
46
|
-
height: 16px;
|
|
47
|
-
background-color: transparent;
|
|
48
|
-
}
|
|
49
|
-
input[type='range']::-webkit-slider-runnable-track {
|
|
50
|
-
width: 100%;
|
|
51
|
-
height: 1px;
|
|
52
|
-
background: white;
|
|
53
|
-
border: none;
|
|
54
|
-
border-radius: 5px;
|
|
55
|
-
}
|
|
56
|
-
input[type='range']::-webkit-slider-thumb {
|
|
57
|
-
-webkit-appearance: none;
|
|
58
|
-
border: none;
|
|
59
|
-
height: 10px;
|
|
60
|
-
width: 10px;
|
|
61
|
-
border-radius: 50%;
|
|
62
|
-
background: white;
|
|
63
|
-
margin-top: -5px;
|
|
64
|
-
}
|
|
65
|
-
input[type='range']:focus {
|
|
66
|
-
outline: none;
|
|
67
|
-
}
|
|
68
|
-
input[type='range']:focus::-webkit-slider-runnable-track {
|
|
69
|
-
background: white;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
input[type='range']::-moz-range-track {
|
|
73
|
-
width: 100%;
|
|
74
|
-
height: 1px;
|
|
75
|
-
background: white;
|
|
76
|
-
border: none;
|
|
77
|
-
border-radius: 5px;
|
|
78
|
-
}
|
|
79
|
-
input[type='range']::-moz-range-thumb {
|
|
80
|
-
border: none;
|
|
81
|
-
height: 10px;
|
|
82
|
-
width: 10px;
|
|
83
|
-
border-radius: 50%;
|
|
84
|
-
background: white;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
input[type='range']:-moz-focusring {
|
|
88
|
-
outline: 1px solid white;
|
|
89
|
-
outline-offset: -1px;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
input[type='range']::-ms-track {
|
|
93
|
-
width: 100%;
|
|
94
|
-
height: 1px;
|
|
95
|
-
background: white;
|
|
96
|
-
border-radius: 10px;
|
|
97
|
-
color: transparent;
|
|
98
|
-
border: none;
|
|
99
|
-
outline: none;
|
|
100
|
-
}
|
|
101
|
-
input[type='range']::-ms-thumb {
|
|
102
|
-
height: 10px;
|
|
103
|
-
width: 10px;
|
|
104
|
-
border-radius: 50%;
|
|
105
|
-
background: white;
|
|
106
|
-
border: none;
|
|
107
|
-
outline: none;
|
|
108
|
-
margin-top: 2px;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
input:focus {
|
|
112
|
-
outline: none;
|
|
113
|
-
opacity: 1;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/* list of joint sliders */
|
|
117
|
-
ul {
|
|
118
|
-
flex: 1;
|
|
119
|
-
overflow-y: auto;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
li {
|
|
123
|
-
font-size: 16px;
|
|
124
|
-
display: flex;
|
|
125
|
-
align-items: center;
|
|
126
|
-
padding: 1px 0;
|
|
127
|
-
|
|
128
|
-
width: 100%;
|
|
129
|
-
user-select: text;
|
|
130
|
-
|
|
131
|
-
transition: background 0.25s ease;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
li[robot-hovered] {
|
|
135
|
-
background: rgba(255, 255, 255, 0.35);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
li:hover {
|
|
139
|
-
background: rgba(255, 255, 255, 0.35);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
li span {
|
|
143
|
-
padding: 0 5px;
|
|
144
|
-
max-width: 125px;
|
|
145
|
-
text-overflow: ellipsis;
|
|
146
|
-
overflow: hidden;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
li input[type='number'] {
|
|
150
|
-
width: 50px;
|
|
151
|
-
overflow: hidden;
|
|
152
|
-
}
|
|
153
|
-
`
|
|
154
|
-
];
|
|
155
|
-
viewer;
|
|
156
|
-
robot;
|
|
157
|
-
render() {
|
|
158
|
-
const { joints = {} } = this.robot || {};
|
|
159
|
-
const { ignoreLimits = false } = this.viewer || {};
|
|
160
|
-
const jointsArray = Object.values(joints);
|
|
161
|
-
return html `
|
|
162
|
-
<ul>
|
|
163
|
-
${jointsArray.map(joint => {
|
|
164
|
-
var { jointType, name, angle, limit } = joint;
|
|
165
|
-
var degVal = Number(angle || 0);
|
|
166
|
-
if (jointType === 'revolute' || jointType === 'continuous') {
|
|
167
|
-
degVal *= RAD2DEG;
|
|
168
|
-
}
|
|
169
|
-
if (Math.abs(degVal) > 1) {
|
|
170
|
-
degVal = degVal.toFixed(1);
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
degVal = degVal.toPrecision(2);
|
|
174
|
-
}
|
|
175
|
-
var sliderMin;
|
|
176
|
-
var sliderMax;
|
|
177
|
-
var inputMin;
|
|
178
|
-
var inputMax;
|
|
179
|
-
if (ignoreLimits || jointType === 'continuous') {
|
|
180
|
-
sliderMin = -6.28;
|
|
181
|
-
sliderMax = 6.28;
|
|
182
|
-
inputMin = -6.28 * RAD2DEG;
|
|
183
|
-
inputMax = 6.28 * RAD2DEG;
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
sliderMin = limit.lower;
|
|
187
|
-
sliderMax = limit.upper;
|
|
188
|
-
inputMin = Number(limit.lower) * RAD2DEG;
|
|
189
|
-
inputMax = Number(limit.upper) * RAD2DEG;
|
|
190
|
-
}
|
|
191
|
-
return html `
|
|
192
|
-
<li joint-type=${jointType} joint-name=${name}>
|
|
193
|
-
<span title=${name}>${name}</span>
|
|
194
|
-
<input
|
|
195
|
-
type="range"
|
|
196
|
-
.value=${String(angle)}
|
|
197
|
-
step="0.0001"
|
|
198
|
-
min=${sliderMin}
|
|
199
|
-
max=${sliderMax}
|
|
200
|
-
@input=${(e) => {
|
|
201
|
-
this.viewer?.setJointValue(name, e.target.value);
|
|
202
|
-
}}
|
|
203
|
-
/>
|
|
204
|
-
<input
|
|
205
|
-
type="number"
|
|
206
|
-
.value=${degVal}
|
|
207
|
-
step="0.0001"
|
|
208
|
-
min=${inputMin}
|
|
209
|
-
max=${inputMax}
|
|
210
|
-
@change=${(e) => {
|
|
211
|
-
this.viewer?.setJointValue(name, Number(e.target.value) * DEG2RAD);
|
|
212
|
-
}}
|
|
213
|
-
/>
|
|
214
|
-
</li>
|
|
215
|
-
`;
|
|
216
|
-
})}
|
|
217
|
-
</ul>
|
|
218
|
-
`;
|
|
219
|
-
}
|
|
220
|
-
updated(changes) {
|
|
221
|
-
if (changes.has('viewer')) {
|
|
222
|
-
this._setupViewer(this.viewer);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
_setupViewer(viewer) {
|
|
226
|
-
if (!viewer) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
this.robot = viewer.robot;
|
|
230
|
-
viewer.addEventListener('urdf-processed', () => {
|
|
231
|
-
this.robot = viewer.robot;
|
|
232
|
-
});
|
|
233
|
-
viewer.addEventListener('ignore-limits-change', () => {
|
|
234
|
-
this.requestUpdate();
|
|
235
|
-
});
|
|
236
|
-
viewer.addEventListener('angle-change', (e) => {
|
|
237
|
-
this.requestUpdate();
|
|
238
|
-
});
|
|
239
|
-
viewer.addEventListener('joint-mouseover', (e) => {
|
|
240
|
-
const j = this.renderRoot.querySelector(`li[joint-name="${e.detail}"]`);
|
|
241
|
-
if (j) {
|
|
242
|
-
j.setAttribute('robot-hovered', 'true');
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
viewer.addEventListener('joint-mouseout', (e) => {
|
|
246
|
-
const j = this.renderRoot.querySelector(`li[joint-name="${e.detail}"]`);
|
|
247
|
-
if (j) {
|
|
248
|
-
j.removeAttribute('robot-hovered');
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
let originalNoAutoRecenter;
|
|
252
|
-
viewer.addEventListener('manipulate-start', (e) => {
|
|
253
|
-
const j = this.renderRoot.querySelector(`li[joint-name="${e.detail}"]`);
|
|
254
|
-
if (j) {
|
|
255
|
-
// ??
|
|
256
|
-
j.scrollIntoView({ block: 'nearest' });
|
|
257
|
-
window.scrollTo(0, 0);
|
|
258
|
-
}
|
|
259
|
-
originalNoAutoRecenter = viewer.noAutoRecenter;
|
|
260
|
-
viewer.noAutoRecenter = true;
|
|
261
|
-
});
|
|
262
|
-
viewer.addEventListener('manipulate-end', (e) => {
|
|
263
|
-
viewer.noAutoRecenter = originalNoAutoRecenter;
|
|
264
|
-
});
|
|
265
|
-
registerDragEvents(viewer, () => {
|
|
266
|
-
this.setColor('#263238');
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
setColor(color) {
|
|
270
|
-
this.viewer.highlightColor = '#' + new THREE.Color(0xffffff).lerp(new THREE.Color(color), 0.35).getHexString();
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
__decorate([
|
|
274
|
-
property({ type: Object })
|
|
275
|
-
], URDFControllerElement.prototype, "viewer", void 0);
|
|
276
|
-
__decorate([
|
|
277
|
-
property({ type: Object })
|
|
278
|
-
], URDFControllerElement.prototype, "robot", void 0);
|
|
279
|
-
URDFControllerElement = __decorate([
|
|
280
|
-
customElement('urdf-controller')
|
|
281
|
-
], URDFControllerElement);
|
|
282
|
-
export default URDFControllerElement;
|
|
283
|
-
//# sourceMappingURL=urdf-controller-element.js.map
|