Skip to content

Commit 18fbe4c

Browse files
authored
Migrate urdf modules to Typescript (#907)
* revert: chore(vite): Temporarily disable type checking and declaration generation for PR Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfTypes): Convert UrdfTypes to TypeScript enum and update references. Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfBox, UrdfTypes): Convert UrdfBox to TypeScript. Add enum of Urdf Attributes to remove magic strings when getting attributes from xml Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfColor): Convert UrdfColor to TypeScript. Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfCylinder): Convert UrdfCylinder to TypeScript, fix parsing warning. Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfJoint, UrdfUtils): Convert UrdfJoint to TypeScript and extract origin parsing logic to UrdfUtils. Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfMaterial): Convert UrdfMaterial to TypeScript. Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfMesh): Convert UrdfMesh to TypeScript. Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfSphere): Convert UrdfSphere to TypeScript. Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfVisual, UrdfUtils): Convert UrdfVisual to TypeScript, add isElement check in UrdfUtils Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfLink): Convert UrdfLink to TypeScript, loop with for-of since ES6 provides it Signed-off-by: Drew Hoener <[email protected]> * refactor(UrdfModel): Convert UrdfModel to TypeScript, replace loops with for-of, and improve type safety Signed-off-by: Drew Hoener <[email protected]> --------- Signed-off-by: Drew Hoener <[email protected]>
1 parent d2d5771 commit 18fbe4c

14 files changed

+372
-340
lines changed

src/urdf/UrdfBox.ts

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,30 @@
44
* @author Russell Toris - [email protected]
55
*/
66

7-
import Vector3 from '../math/Vector3.js';
8-
import * as UrdfTypes from './UrdfTypes.js';
7+
import { Vector3 } from '../math/index.js';
8+
import { UrdfAttrs, UrdfType, type UrdfDefaultOptions } from './UrdfTypes.js';
9+
import type { Optional, Nullable } from '../types/interface-types.js';
910

1011
/**
1112
* A Box element in a URDF.
1213
*/
1314
export default class UrdfBox {
14-
/** @type {Vector3 | null} */
15-
dimension;
16-
/**
17-
* @param {Object} options
18-
* @param {Element} options.xml - The XML element to parse.
19-
*/
20-
constructor(options) {
21-
this.type = UrdfTypes.URDF_BOX;
15+
type: UrdfType;
16+
dimension: Nullable<Vector3> = null;
17+
18+
constructor({ xml }: UrdfDefaultOptions) {
19+
this.type = UrdfType.BOX;
2220

2321
// Parse the xml string
24-
var xyz = options.xml.getAttribute('size')?.split(' ');
25-
if (xyz) {
26-
this.dimension = new Vector3({
27-
x: parseFloat(xyz[0]),
28-
y: parseFloat(xyz[1]),
29-
z: parseFloat(xyz[2])
30-
});
31-
} else {
32-
this.dimension = null;
22+
const size: Optional<string[]> = xml.getAttribute(UrdfAttrs.Size)?.split(' ');
23+
if (!size || size.length !== 3) {
24+
return;
3325
}
26+
27+
this.dimension = new Vector3({
28+
x: parseFloat(size[0]),
29+
y: parseFloat(size[1]),
30+
z: parseFloat(size[2])
31+
});
3432
}
3533
}

src/urdf/UrdfColor.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,41 @@
44
* @author Russell Toris - [email protected]
55
*/
66

7+
import { UrdfAttrs, type UrdfDefaultOptions } from './UrdfTypes.js';
8+
import type { Optional } from '../types/interface-types.js';
9+
710
/**
811
* A Color element in a URDF.
912
*/
1013
export default class UrdfColor {
14+
15+
/**
16+
* Color Red, [0, 1]
17+
*/
18+
r = 0.0;
19+
/**
20+
* Color Green, [0, 1]
21+
*/
22+
g = 0.0;
23+
/**
24+
* Color Blue, [0, 1]
25+
*/
26+
b = 0.0;
1127
/**
12-
* @param {Object} options
13-
* @param {Element} options.xml - The XML element to parse.
28+
* Alpha/Opacity, [0, 1]
1429
*/
15-
constructor(options) {
30+
a = 1.0;
31+
32+
constructor({ xml }: UrdfDefaultOptions) {
1633
// Parse the xml string
17-
var rgba = options.xml.getAttribute('rgba')?.split(' ');
18-
if (rgba) {
19-
this.r = parseFloat(rgba[0]);
20-
this.g = parseFloat(rgba[1]);
21-
this.b = parseFloat(rgba[2]);
22-
this.a = parseFloat(rgba[3]);
34+
const rgba: Optional<string[]> = xml.getAttribute(UrdfAttrs.Rgba)?.split(' ');
35+
if (!rgba || rgba.length !== 4) {
36+
return;
2337
}
38+
39+
this.r = parseFloat(rgba[0]);
40+
this.g = parseFloat(rgba[1]);
41+
this.b = parseFloat(rgba[2]);
42+
this.a = parseFloat(rgba[3]);
2443
}
2544
}

src/urdf/UrdfCylinder.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@
44
* @author Russell Toris - [email protected]
55
*/
66

7-
import * as UrdfTypes from './UrdfTypes.js';
7+
import { type UrdfDefaultOptions, UrdfType, UrdfAttrs } from './UrdfTypes.js';
88

99
/**
1010
* A Cylinder element in a URDF.
1111
*/
1212
export default class UrdfCylinder {
13-
/**
14-
* @param {Object} options
15-
* @param {Element} options.xml - The XML element to parse.
16-
*/
17-
constructor(options) {
18-
this.type = UrdfTypes.URDF_CYLINDER;
19-
// @ts-expect-error -- possibly null
20-
this.length = parseFloat(options.xml.getAttribute('length'));
21-
// @ts-expect-error -- possibly null
22-
this.radius = parseFloat(options.xml.getAttribute('radius'));
13+
14+
type: UrdfType;
15+
length: number;
16+
radius: number;
17+
18+
constructor({ xml }: UrdfDefaultOptions) {
19+
this.type = UrdfType.CYLINDER;
20+
21+
this.length = parseFloat(xml.getAttribute(UrdfAttrs.Length) ?? 'NaN');
22+
this.radius = parseFloat(xml.getAttribute(UrdfAttrs.Radius) ?? 'NaN');
2323
}
2424
}

src/urdf/UrdfJoint.ts

Lines changed: 27 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,93 +3,49 @@
33
* @author David V. Lu!! - [email protected]
44
*/
55

6-
import Pose from '../math/Pose.js';
7-
import Vector3 from '../math/Vector3.js';
8-
import Quaternion from '../math/Quaternion.js';
6+
import { UrdfAttrs, type UrdfDefaultOptions } from './UrdfTypes.js';
7+
import { Pose } from '../math/index.js';
8+
import { parseUrdfOrigin } from './UrdfUtils.js';
9+
import type { Nullable } from '../types/interface-types.js';
910

1011
/**
1112
* A Joint element in a URDF.
1213
*/
1314
export default class UrdfJoint {
14-
/**
15-
* @param {Object} options
16-
* @param {Element} options.xml - The XML element to parse.
17-
*/
18-
constructor(options) {
19-
this.name = options.xml.getAttribute('name');
20-
this.type = options.xml.getAttribute('type');
2115

22-
var parents = options.xml.getElementsByTagName('parent');
16+
name: string;
17+
type: Nullable<string>;
18+
parent: Nullable<string> = null;
19+
child: Nullable<string> = null;
20+
minval = NaN;
21+
maxval = NaN;
22+
origin: Pose = new Pose();
23+
24+
25+
constructor({xml}: UrdfDefaultOptions) {
26+
this.name = xml.getAttribute(UrdfAttrs.Name) ?? 'unknown_name';
27+
this.type = xml.getAttribute(UrdfAttrs.Type);
28+
29+
const parents = xml.getElementsByTagName(UrdfAttrs.Parent);
2330
if (parents.length > 0) {
24-
this.parent = parents[0].getAttribute('link');
31+
this.parent = parents[0].getAttribute(UrdfAttrs.Link);
2532
}
2633

27-
var children = options.xml.getElementsByTagName('child');
34+
const children = xml.getElementsByTagName(UrdfAttrs.Child);
2835
if (children.length > 0) {
29-
this.child = children[0].getAttribute('link');
36+
this.child = children[0].getAttribute(UrdfAttrs.Link);
3037
}
3138

32-
var limits = options.xml.getElementsByTagName('limit');
39+
const limits = xml.getElementsByTagName(UrdfAttrs.Limit);
3340
if (limits.length > 0) {
34-
this.minval = parseFloat(limits[0].getAttribute('lower') || 'NaN');
35-
this.maxval = parseFloat(limits[0].getAttribute('upper') || 'NaN');
41+
this.minval = parseFloat(limits[0].getAttribute(UrdfAttrs.Lower) ?? 'NaN');
42+
this.maxval = parseFloat(limits[0].getAttribute(UrdfAttrs.Upper) ?? 'NaN');
3643
}
3744

3845
// Origin
39-
var origins = options.xml.getElementsByTagName('origin');
40-
if (origins.length === 0) {
41-
// use the identity as the default
42-
this.origin = new Pose();
43-
} else {
44-
// Check the XYZ
45-
var xyzValue = origins[0].getAttribute('xyz');
46-
var position = new Vector3();
47-
if (xyzValue) {
48-
var xyz = xyzValue.split(' ');
49-
position = new Vector3({
50-
x: parseFloat(xyz[0]),
51-
y: parseFloat(xyz[1]),
52-
z: parseFloat(xyz[2])
53-
});
54-
}
55-
56-
// Check the RPY
57-
var rpyValue = origins[0].getAttribute('rpy');
58-
var orientation = new Quaternion();
59-
if (rpyValue) {
60-
var rpy = rpyValue.split(' ');
61-
// Convert from RPY
62-
var roll = parseFloat(rpy[0]);
63-
var pitch = parseFloat(rpy[1]);
64-
var yaw = parseFloat(rpy[2]);
65-
var phi = roll / 2.0;
66-
var the = pitch / 2.0;
67-
var psi = yaw / 2.0;
68-
var x =
69-
Math.sin(phi) * Math.cos(the) * Math.cos(psi) -
70-
Math.cos(phi) * Math.sin(the) * Math.sin(psi);
71-
var y =
72-
Math.cos(phi) * Math.sin(the) * Math.cos(psi) +
73-
Math.sin(phi) * Math.cos(the) * Math.sin(psi);
74-
var z =
75-
Math.cos(phi) * Math.cos(the) * Math.sin(psi) -
76-
Math.sin(phi) * Math.sin(the) * Math.cos(psi);
77-
var w =
78-
Math.cos(phi) * Math.cos(the) * Math.cos(psi) +
79-
Math.sin(phi) * Math.sin(the) * Math.sin(psi);
80-
81-
orientation = new Quaternion({
82-
x: x,
83-
y: y,
84-
z: z,
85-
w: w
86-
});
87-
orientation.normalize();
88-
}
89-
this.origin = new Pose({
90-
position: position,
91-
orientation: orientation
92-
});
46+
const origins = xml.getElementsByTagName(UrdfAttrs.Origin);
47+
if (origins.length > 0) {
48+
this.origin = parseUrdfOrigin(origins[0]);
9349
}
9450
}
9551
}

src/urdf/UrdfLink.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@
55
*/
66

77
import UrdfVisual from './UrdfVisual.js';
8+
import { UrdfAttrs, type UrdfDefaultOptions } from './UrdfTypes.js';
89

910
/**
1011
* A Link element in a URDF.
1112
*/
1213
export default class UrdfLink {
13-
/**
14-
* @param {Object} options
15-
* @param {Element} options.xml - The XML element to parse.
16-
*/
17-
constructor(options) {
18-
this.name = options.xml.getAttribute('name');
19-
this.visuals = [];
20-
var visuals = options.xml.getElementsByTagName('visual');
2114

22-
for (var i = 0; i < visuals.length; i++) {
15+
name: string;
16+
visuals: UrdfVisual[] = [];
17+
18+
constructor({ xml }: UrdfDefaultOptions) {
19+
this.name = xml.getAttribute(UrdfAttrs.Name) ?? 'unknown_name';
20+
const visuals = xml.getElementsByTagName(UrdfAttrs.Visuals);
21+
22+
for (const visual of visuals) {
2323
this.visuals.push(
2424
new UrdfVisual({
25-
xml: visuals[i]
25+
xml: visual
2626
})
2727
);
2828
}

src/urdf/UrdfMaterial.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,43 @@
55
*/
66

77
import UrdfColor from './UrdfColor.js';
8+
import { UrdfAttrs, type UrdfDefaultOptions } from './UrdfTypes.js';
9+
import type { Nullable } from '../types/interface-types.js';
810

911
/**
1012
* A Material element in a URDF.
1113
*/
1214
export default class UrdfMaterial {
13-
/** @type {string | null} */
14-
textureFilename = null;
15-
/** @type {UrdfColor | null} */
16-
color = null;
17-
/**
18-
* @param {Object} options
19-
* @param {Element} options.xml - The XML element to parse.
20-
*/
21-
constructor(options) {
22-
23-
this.name = options.xml.getAttribute('name');
15+
16+
name: string;
17+
textureFilename: Nullable<string> = null;
18+
color: Nullable<UrdfColor> = null;
19+
20+
constructor({ xml }: UrdfDefaultOptions) {
21+
22+
this.name = xml.getAttribute(UrdfAttrs.Name) ?? 'unknown_name';
2423

2524
// Texture
26-
var textures = options.xml.getElementsByTagName('texture');
25+
const textures = xml.getElementsByTagName(UrdfAttrs.Texture);
2726
if (textures.length > 0) {
28-
this.textureFilename = textures[0].getAttribute('filename');
27+
this.textureFilename = textures[0].getAttribute(UrdfAttrs.Filename);
2928
}
3029

3130
// Color
32-
var colors = options.xml.getElementsByTagName('color');
31+
const colors = xml.getElementsByTagName(UrdfAttrs.Color);
3332
if (colors.length > 0) {
3433
// Parse the RBGA string
3534
this.color = new UrdfColor({
3635
xml: colors[0]
3736
});
3837
}
3938
}
39+
4040
isLink() {
4141
return this.color === null && this.textureFilename === null;
4242
}
43-
assign(obj) {
43+
44+
assign(obj: UrdfMaterial): this & UrdfMaterial {
4445
return Object.assign(this, obj);
4546
}
4647
}

0 commit comments

Comments
 (0)