Socket
Socket
Sign inDemoInstall

urdf-loader

Package Overview
Dependencies
Maintainers
1
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

urdf-loader - npm Package Compare versions

Comparing version 0.9.2 to 0.9.3

src/URDFDragControls.js

9

CHANGELOG.md

@@ -7,2 +7,11 @@ # Changelog

## [0.9.3] - 2021-01-19
### Fixed
- Unnecessary creation of a new quaternion when setting a joint angle.
- Throw a human readable error when fetch fails.
- The model failing to clone if the object names were changed.
### Added
- Ability to set the `packages` option to a function.
## [0.9.2] - 2020-10-23

@@ -9,0 +18,0 @@ ### Added

2

package.json
{
"name": "urdf-loader",
"version": "0.9.2",
"version": "0.9.3",
"description": "URDF Loader for THREE.js and webcomponent viewer",

@@ -5,0 +5,0 @@ "main": "umd/URDFLoader.js",

# urdf-loader
[![npm version](https://img.shields.io/npm/v/urdf-loader.svg?style=flat-square)](https://www.npmjs.com/package/urdf-loader)
[![travis build](https://img.shields.io/travis/gkjohnson/urdf-loaders/master.svg?style=flat-square)](https://travis-ci.com/gkjohnson/urdf-loaders)
[![build](https://img.shields.io/github/workflow/status/gkjohnson/urdf-loaders/Node.js%20CI?style=flat-square&label=build)](https://github.com/gkjohnson/urdf-loaders/actions)
[![lgtm code quality](https://img.shields.io/lgtm/grade/javascript/g/gkjohnson/urdf-loaders.svg?style=flat-square&label=code-quality)](https://lgtm.com/projects/g/gkjohnson/urdf-loaders/)

@@ -9,4 +9,6 @@

[Simple example with VR here!](https://gkjohnson.github.io/urdf-loaders/javascript/example/simple.html)
[Basic loader example here!](https://gkjohnson.github.io/urdf-loaders/javascript/example/simple.html)
[VR example here!](https://gkjohnson.github.io/urdf-loaders/javascript/example/vr.html)
[Drag and drop web component tool here!](https://gkjohnson.github.io/urdf-loaders/javascript/example/index.html)

@@ -44,5 +46,5 @@

#### Custom Mesh Loader
#### Custom Mesh Loader & Error Handling
Adding a custom mesh loader.
Implementing custom error handling and / or adding a custom loader for meshes can be done using the [loadMeshCb](#loadMeshCb) callback.

@@ -59,7 +61,18 @@ ```js

const gltfLoader = new GLTFLoader( manager );
gltfLoader.load( path, result => {
gltfLoader.load(
path,
result => {
onComplete( result.scene );
onComplete( result.scene );
} );
},
undefined,
err => {
// try to load again, notify user, etc
onComplete( null, err );
}
);

@@ -112,3 +125,3 @@ };

```js
packages = '' : String | Object
packages = '' : String | Object | ( pkg : String ) => String
```

@@ -129,2 +142,4 @@

If the setting is set to a function then it takes the package name and is expected to return the package path.
### .loadMeshCb

@@ -131,0 +146,0 @@

import * as THREE from 'three';
import URDFViewer from './urdf-viewer-element.js';
import { PointerURDFDragControls } from './URDFDragControls.js';

@@ -40,40 +41,2 @@ // urdf-manipulator element

const el = this.renderer.domElement;
// Saved mouse data between frames and initial
// click point in space
const mouse = new THREE.Vector2();
const lastMouse = new THREE.Vector2();
const clickPoint = new THREE.Vector3();
// Reuseable variables
const raycaster = new THREE.Raycaster();
const delta = new THREE.Vector2();
const plane = new THREE.Plane();
const line = new THREE.Line3();
// The joint being manipulated
let dragging = null;
const toMouseCoord = (e, v) => {
v.x = ((e.pageX - el.offsetLeft) / el.offsetWidth) * 2 - 1;
v.y = -((e.pageY - el.offsetTop) / el.offsetHeight) * 2 + 1;
};
// Get which part of the robot is hit by the mouse click
const getCollisions = m => {
if (!this.robot) return [];
raycaster.setFromCamera(m, this.camera);
const meshes = [];
this.robot.traverse(c => c.type === 'Mesh' && meshes.push(c));
return raycaster.intersectObjects(meshes);
};
const isJoint = j => {

@@ -85,22 +48,2 @@

// Find the nearest parent that is a joint
const findNearestJoint = m => {
let curr = m;
while (curr) {
if (isJoint(curr)) {
break;
}
curr = curr.parent;
}
return curr;
};
// Highlight the link geometry under a joint

@@ -146,221 +89,41 @@ const highlightLinkGeometry = (m, revert) => {

const temp = new THREE.Vector3();
const intersect1 = new THREE.Vector3();
const intersect2 = new THREE.Vector3();
const el = this.renderer.domElement;
// Get the changed angle between mouse position 1 and 2
// when manipulating target
const getAngle = (tg, m1, m2) => {
const dragControls = new PointerURDFDragControls(this.scene, this.camera, el);
dragControls.onDragStart = joint => {
// TODO: Why is the constant negated?
plane.normal.copy(tg.axis).transformDirection(tg.matrixWorld).normalize();
plane.constant = -plane.normal.dot(clickPoint);
this.dispatchEvent(new CustomEvent('manipulate-start', { bubbles: true, cancelable: true, detail: joint.name }));
this.controls.enabled = false;
this.redraw();
// If the camera is looking at the rotation axis at a skewed angle
temp.copy(this.camera.position).sub(clickPoint).normalize();
if (Math.abs(temp.dot(plane.normal)) < 0.2) {
};
dragControls.onDragEnd = joint => {
// distance to the clicked point
const dist = temp.copy(clickPoint).sub(this.camera.position).length() * 0.9;
this.dispatchEvent(new CustomEvent('manipulate-end', { bubbles: true, cancelable: true, detail: joint.name }));
this.controls.enabled = true;
this.redraw();
// Get the point closest to the original clicked point
// and use that as center of the rotation axis
temp.set(0, 0, 0).applyMatrix4(tg.matrixWorld);
temp.addScaledVector(plane.normal, -plane.distanceToPoint(temp));
// Project out from the camera
raycaster.setFromCamera(m1, this.camera);
intersect1.copy(raycaster.ray.origin).add(
raycaster.ray.direction.normalize().multiplyScalar(dist),
);
intersect1.sub(temp);
raycaster.setFromCamera(m2, this.camera);
intersect2.copy(raycaster.ray.origin).add(
raycaster.ray.direction.normalize().multiplyScalar(dist),
);
intersect2.sub(temp);
temp.crossVectors(intersect2, intersect1).normalize();
// Multiply by a magic number to make it feel good
return temp.dot(plane.normal) * intersect2.angleTo(intersect1) * 2;
} else {
// Get the point closest to the original clicked point
// and use that as center of the rotation axis
temp.set(0, 0, 0).applyMatrix4(tg.matrixWorld);
temp.addScaledVector(plane.normal, -plane.distanceToPoint(temp));
// project onto the plane of rotation
raycaster.setFromCamera(m1, this.camera);
line.start.copy(raycaster.ray.origin);
line.end.copy(raycaster.ray.origin).add(raycaster.ray.direction.normalize().multiplyScalar(1e5));
plane.intersectLine(line, intersect1);
intersect1.sub(temp);
raycaster.setFromCamera(m2, this.camera);
line.start.copy(raycaster.ray.origin);
line.end.copy(raycaster.ray.origin).add(raycaster.ray.direction.normalize().multiplyScalar(1e5));
plane.intersectLine(line, intersect2);
intersect2.sub(temp);
temp.crossVectors(intersect2, intersect1);
return Math.sign(temp.dot(plane.normal)) * intersect2.angleTo(intersect1);
}
};
dragControls.updateJoint = (joint, angle) => {
// Get the amount to move the prismatic joint based on the mouse move
const getMove = (tg, m1, m2) => {
this.setJointValue(joint.name, angle);
const dist = temp.copy(clickPoint).sub(this.camera.position).length();
raycaster.setFromCamera(m1, this.camera);
raycaster.ray.direction.normalize().multiplyScalar(dist);
intersect1.copy(raycaster.ray.origin).add(raycaster.ray.direction);
raycaster.setFromCamera(m2, this.camera);
raycaster.ray.direction.normalize().multiplyScalar(dist);
intersect2.copy(raycaster.ray.origin).add(raycaster.ray.direction);
temp.copy(intersect2).sub(intersect1);
plane.normal.copy(tg.axis).transformDirection(tg.parent.matrixWorld).normalize();
return temp.length() * -Math.sign(temp.dot(plane.normal));
};
dragControls.onHover = joint => {
el.addEventListener('mousedown', e => {
highlightLinkGeometry(joint, false);
this.dispatchEvent(new CustomEvent('joint-mouseout', { bubbles: true, cancelable: true, detail: joint.name }));
this.redraw();
if (this.disableDragging) return;
toMouseCoord(e, mouse);
lastMouse.copy(mouse);
// get the information on the clicked item
// and set the dragged joint
const target = getCollisions(mouse).shift();
if (target) {
dragging = findNearestJoint(target.object);
if (dragging) {
clickPoint.copy(target.point);
this.dispatchEvent(new CustomEvent('manipulate-start', { bubbles: true, cancelable: true, detail: dragging.name }));
this.controls.enabled = false;
}
}
}, true);
let hovered = null;
this._mouseMoveFunc = e => {
toMouseCoord(e, mouse);
delta.copy(mouse).sub(lastMouse);
// Keep track of the hovered item. If an item is being
// dragged, then it is considered hovered
const wasHovered = hovered;
if (hovered) {
hovered = null;
}
if (dragging == null && this.disableDragging === false) {
const collision = getCollisions(mouse).shift() || null;
const joint = collision && findNearestJoint(collision.object);
if (joint) {
hovered = joint;
}
} else if (dragging) {
hovered = dragging;
}
// Highlight the meshes and broadcast events if the hovered item changed
if (hovered !== wasHovered) {
if (wasHovered) {
highlightLinkGeometry(wasHovered, true);
this.dispatchEvent(new CustomEvent('joint-mouseout', { bubbles: true, cancelable: true, detail: wasHovered.name }));
}
if (hovered) {
highlightLinkGeometry(hovered, false);
this.dispatchEvent(new CustomEvent('joint-mouseover', { bubbles: true, cancelable: true, detail: hovered.name }));
}
this.redraw();
}
// Apply the manipulation
if (dragging !== null) {
let delta = null;
if (dragging.jointType === 'revolute' || dragging.jointType === 'continuous') {
delta = getAngle(dragging, mouse, lastMouse);
} else if (dragging.jointType === 'prismatic') {
delta = getMove(dragging, mouse, lastMouse);
} else {
// Not supported
}
if (delta) {
this.setJointValue(dragging.name, dragging.angle + delta);
}
}
lastMouse.copy(mouse);
};
dragControls.onUnhover = joint => {
// Clean up
this._mouseUpFunc = e => {
highlightLinkGeometry(joint, true);
this.dispatchEvent(new CustomEvent('joint-mouseover', { bubbles: true, cancelable: true, detail: joint.name }));
this.redraw();
if (dragging) {
this.dispatchEvent(new CustomEvent('manipulate-end', { bubbles: true, cancelable: true, detail: dragging.name }));
dragging = null;
this.controls.enabled = true;
}
};
}
this.dragControls = dragControls;
connectedCallback() {
super.connectedCallback();
window.addEventListener('mousemove', this._mouseMoveFunc, true);
window.addEventListener('mouseup', this._mouseUpFunc, true);
}

@@ -371,4 +134,3 @@

super.disconnectedCallback();
window.removeEventListener('mousemove', this._mouseMoveFunc, true);
window.removeEventListener('mouseup', this._mouseUpFunc, true);
this.dragControls.dispose();

@@ -375,0 +137,0 @@ }

@@ -1,4 +0,4 @@

import { Object3D, Quaternion } from 'three';
import { Object3D } from 'three';
class URDFCollider extends Object3D {
class URDFBase extends Object3D {

@@ -8,5 +8,4 @@ constructor(...args) {

super(...args);
this.isURDFCollider = true;
this.type = 'URDFCollider';
this.urdfNode = null;
this.urdfName = '';

@@ -18,3 +17,5 @@ }

super.copy(source, recursive);
this.urdfNode = source.urdfNode;
this.urdfName = source.urdfName;

@@ -27,3 +28,3 @@ return this;

class URDFVisual extends Object3D {
class URDFCollider extends URDFBase {

@@ -33,15 +34,17 @@ constructor(...args) {

super(...args);
this.isURDFVisual = true;
this.type = 'URDFVisual';
this.urdfNode = null;
this.isURDFCollider = true;
this.type = 'URDFCollider';
}
copy(source, recursive) {
}
super.copy(source, recursive);
this.urdfNode = source.urdfNode;
class URDFVisual extends URDFBase {
return this;
constructor(...args) {
super(...args);
this.isURDFVisual = true;
this.type = 'URDFVisual';
}

@@ -51,3 +54,3 @@

class URDFLink extends Object3D {
class URDFLink extends URDFBase {

@@ -59,18 +62,8 @@ constructor(...args) {

this.type = 'URDFLink';
this.urdfNode = null;
}
copy(source, recursive) {
super.copy(source, recursive);
this.urdfNode = source.urdfNode;
return this;
}
}
class URDFJoint extends Object3D {
class URDFJoint extends URDFBase {

@@ -125,3 +118,2 @@ get jointType() {

this.urdfNode = null;
this.jointValue = null;

@@ -143,3 +135,2 @@ this.jointType = 'fixed';

this.urdfNode = source.urdfNode;
this.jointType = source.jointType;

@@ -184,3 +175,3 @@ this.axis = source.axis ? source.axis.clone() : null;

if (angle == null) return false;
if (angle === this.angle) return false;
if (angle === this.jointValue[0]) return false;

@@ -194,6 +185,5 @@ if (!this.ignoreLimits && this.jointType === 'revolute') {

// FromAxisAngle seems to rotate the opposite of the
// expected angle for URDF, so negate it here
const delta = new Quaternion().setFromAxisAngle(this.axis, angle);
this.quaternion.multiplyQuaternions(this.origQuaternion, delta);
this.quaternion
.setFromAxisAngle(this.axis, angle)
.premultiply(this.origQuaternion);

@@ -218,3 +208,3 @@ if (this.jointValue[0] !== angle) {

if (pos == null) return false;
if (pos === this.angle) return false;
if (pos === this.jointValue[0]) return false;

@@ -291,23 +281,23 @@ if (!this.ignoreLimits) {

if (c.isURDFJoint && c.name in source.joints) {
if (c.isURDFJoint && c.urdfName in source.joints) {
this.joints[c.name] = c;
this.joints[c.urdfName] = c;
}
if (c.isURDFLink && c.name in source.links) {
if (c.isURDFLink && c.urdfName in source.links) {
this.links[c.name] = c;
this.links[c.urdfName] = c;
}
if (c.isURDFCollider && c.name in source.colliders) {
if (c.isURDFCollider && c.urdfName in source.colliders) {
this.colliders[c.name] = c;
this.colliders[c.urdfName] = c;
}
if (c.isURDFVisual && c.name in source.visual) {
if (c.isURDFVisual && c.urdfName in source.visual) {
this.visual[c.name] = c;
this.visual[c.urdfName] = c;

@@ -314,0 +304,0 @@ }

@@ -97,8 +97,16 @@ import * as THREE from 'three';

if (onProgress) {
if (res.ok) {
onProgress(null);
if (onProgress) {
onProgress(null);
}
return res.text();
} else {
throw new Error(`URDFLoader: Failed to load url '${ urdfPath }' with error code ${ res.status } : ${ res.statusText }.`);
}
return res.text();

@@ -176,2 +184,6 @@ })

} else if (packages instanceof Function) {
return packages(targetPkg) + '/' + relPath;
} else if (typeof packages === 'object') {

@@ -283,2 +295,3 @@

obj.name = joint.getAttribute('name');
obj.urdfName = obj.name;
obj.jointType = jointType;

@@ -349,2 +362,3 @@

target.name = link.getAttribute('name');
target.urdfName = target.name;
target.urdfNode = link;

@@ -364,2 +378,3 @@

v.name = name;
v.urdfName = name;
visualMap[name] = v;

@@ -385,2 +400,3 @@

c.name = name;
c.urdfName = name;
colliderMap[name] = c;

@@ -387,0 +403,0 @@

@@ -11,360 +11,450 @@ (function (global, factory) {

// urdf-manipulator element
// Displays a URDF model that can be manipulated with the mouse
// Find the nearest parent that is a joint
function isJoint(j) {
// Events
// joint-mouseover: Fired when a joint is hovered over
// joint-mouseout: Fired when a joint is no longer hovered over
// manipulate-start: Fires when a joint is manipulated
// manipulate-end: Fires when a joint is done being manipulated
class URDFManipulator extends URDFViewer__default['default'] {
return j.isURDFJoint && j.jointType !== 'fixed';
static get observedAttributes() {
};
return ['highlight-color', ...super.observedAttributes];
function findNearestJoint(child) {
}
let curr = child;
while (curr) {
get disableDragging() { return this.hasAttribute('disable-dragging'); }
set disableDragging(val) { val ? this.setAttribute('disable-dragging', !!val) : this.removeAttribute('disable-dragging'); }
if (isJoint(curr)) {
get highlightColor() { return this.getAttribute('highlight-color') || '#FFFFFF'; }
set highlightColor(val) { val ? this.setAttribute('highlight-color', val) : this.removeAttribute('highlight-color'); }
return curr;
constructor(...args) {
}
super(...args);
curr = curr.parent;
// The highlight material
this.highlightMaterial =
new THREE.MeshPhongMaterial({
shininess: 10,
color: this.highlightColor,
emissive: this.highlightColor,
emissiveIntensity: 0.25,
});
}
const el = this.renderer.domElement;
return curr;
// Saved mouse data between frames and initial
// click point in space
const mouse = new THREE.Vector2();
const lastMouse = new THREE.Vector2();
const clickPoint = new THREE.Vector3();
};
// Reuseable variables
const raycaster = new THREE.Raycaster();
const delta = new THREE.Vector2();
const plane = new THREE.Plane();
const line = new THREE.Line3();
const prevHitPoint = new THREE.Vector3();
const newHitPoint = new THREE.Vector3();
const pivotPoint = new THREE.Vector3();
const tempVector = new THREE.Vector3();
const tempVector2 = new THREE.Vector3();
const projectedStartPoint = new THREE.Vector3();
const projectedEndPoint = new THREE.Vector3();
const plane = new THREE.Plane();
class URDFDragControls {
// The joint being manipulated
let dragging = null;
constructor(scene) {
const toMouseCoord = (e, v) => {
this.enabled = true;
this.scene = scene;
this.raycaster = new THREE.Raycaster();
this.initialGrabPoint = new THREE.Vector3();
v.x = ((e.pageX - el.offsetLeft) / el.offsetWidth) * 2 - 1;
v.y = -((e.pageY - el.offsetTop) / el.offsetHeight) * 2 + 1;
this.hitDistance = -1;
this.hovered = null;
this.manipulating = null;
};
}
// Get which part of the robot is hit by the mouse click
const getCollisions = m => {
update() {
if (!this.robot) return [];
const {
raycaster,
hovered,
manipulating,
scene,
} = this;
raycaster.setFromCamera(m, this.camera);
if (manipulating) {
const meshes = [];
this.robot.traverse(c => c.type === 'Mesh' && meshes.push(c));
return;
return raycaster.intersectObjects(meshes);
}
};
let hoveredJoint = null;
const intersections = raycaster.intersectObject(scene, true);
if (intersections.length !== 0) {
const isJoint = j => {
const hit = intersections[0];
this.hitDistance = hit.distance;
hoveredJoint = findNearestJoint(hit.object);
this.initialGrabPoint.copy(hit.point);
return j.isURDFJoint && j.jointType !== 'fixed';
}
};
if (hoveredJoint !== hovered) {
// Find the nearest parent that is a joint
const findNearestJoint = m => {
if (hovered) {
let curr = m;
while (curr) {
this.onUnhover(hovered);
if (isJoint(curr)) {
}
break;
this.hovered = hoveredJoint;
}
if (hoveredJoint) {
curr = curr.parent;
this.onHover(hoveredJoint);
}
return curr;
}
};
}
// Highlight the link geometry under a joint
const highlightLinkGeometry = (m, revert) => {
updateJoint(joint, angle) {
const traverse = c => {
joint.setJointValue(angle);
// Set or revert the highlight color
if (c.type === 'Mesh') {
}
if (revert) {
onDragStart(joint) {
c.material = c.__origMaterial;
delete c.__origMaterial;
}
} else {
onDragEnd(joint) {
c.__origMaterial = c.material;
c.material = this.highlightMaterial;
}
}
onHover(joint) {
}
}
// Look into the children and stop if the next child is
// another joint
if (c === m || !isJoint(c)) {
onUnhover(joint) {
for (let i = 0; i < c.children.length; i++) {
}
traverse(c.children[i]);
getRevoluteDelta(joint, startPoint, endPoint) {
}
// set up the plane
tempVector
.copy(joint.axis)
.transformDirection(joint.matrixWorld)
.normalize();
pivotPoint
.set(0, 0, 0)
.applyMatrix4(joint.matrixWorld);
plane
.setFromNormalAndCoplanarPoint(tempVector, pivotPoint);
}
// project the drag points onto the plane
plane.projectPoint(startPoint, projectedStartPoint);
plane.projectPoint(endPoint, projectedEndPoint);
};
// get the directions relative to the pivot
projectedStartPoint.sub(pivotPoint);
projectedEndPoint.sub(pivotPoint);
traverse(m);
tempVector.crossVectors(projectedStartPoint, projectedEndPoint);
};
const direction = Math.sign(tempVector.dot(plane.normal));
return direction * projectedEndPoint.angleTo(projectedStartPoint);
const temp = new THREE.Vector3();
const intersect1 = new THREE.Vector3();
const intersect2 = new THREE.Vector3();
}
// Get the changed angle between mouse position 1 and 2
// when manipulating target
const getAngle = (tg, m1, m2) => {
getPrismaticDelta(joint, startPoint, endPoint) {
// TODO: Why is the constant negated?
plane.normal.copy(tg.axis).transformDirection(tg.matrixWorld).normalize();
plane.constant = -plane.normal.dot(clickPoint);
tempVector.subVectors(endPoint, startPoint);
plane
.normal
.copy(joint.axis)
.transformDirection(joint.parent.matrixWorld)
.normalize();
// If the camera is looking at the rotation axis at a skewed angle
temp.copy(this.camera.position).sub(clickPoint).normalize();
if (Math.abs(temp.dot(plane.normal)) < 0.2) {
return tempVector.dot(plane.normal);
// distance to the clicked point
const dist = temp.copy(clickPoint).sub(this.camera.position).length() * 0.9;
}
// Get the point closest to the original clicked point
// and use that as center of the rotation axis
temp.set(0, 0, 0).applyMatrix4(tg.matrixWorld);
temp.addScaledVector(plane.normal, -plane.distanceToPoint(temp));
moveRay(toRay) {
// Project out from the camera
raycaster.setFromCamera(m1, this.camera);
intersect1.copy(raycaster.ray.origin).add(
raycaster.ray.direction.normalize().multiplyScalar(dist),
);
intersect1.sub(temp);
const { raycaster, hitDistance, manipulating } = this;
const { ray } = raycaster;
raycaster.setFromCamera(m2, this.camera);
intersect2.copy(raycaster.ray.origin).add(
raycaster.ray.direction.normalize().multiplyScalar(dist),
);
intersect2.sub(temp);
if (manipulating) {
temp.crossVectors(intersect2, intersect1).normalize();
ray.at(hitDistance, prevHitPoint);
toRay.at(hitDistance, newHitPoint);
// Multiply by a magic number to make it feel good
return temp.dot(plane.normal) * intersect2.angleTo(intersect1) * 2;
let delta = 0;
if (manipulating.jointType === 'revolute' || manipulating.jointType === 'continuous') {
} else {
delta = this.getRevoluteDelta(manipulating, prevHitPoint, newHitPoint);
// Get the point closest to the original clicked point
// and use that as center of the rotation axis
temp.set(0, 0, 0).applyMatrix4(tg.matrixWorld);
temp.addScaledVector(plane.normal, -plane.distanceToPoint(temp));
} else if (manipulating.jointType === 'prismatic') {
// project onto the plane of rotation
raycaster.setFromCamera(m1, this.camera);
line.start.copy(raycaster.ray.origin);
line.end.copy(raycaster.ray.origin).add(raycaster.ray.direction.normalize().multiplyScalar(1e5));
plane.intersectLine(line, intersect1);
intersect1.sub(temp);
delta = this.getPrismaticDelta(manipulating, prevHitPoint, newHitPoint);
raycaster.setFromCamera(m2, this.camera);
line.start.copy(raycaster.ray.origin);
line.end.copy(raycaster.ray.origin).add(raycaster.ray.direction.normalize().multiplyScalar(1e5));
plane.intersectLine(line, intersect2);
intersect2.sub(temp);
}
temp.crossVectors(intersect2, intersect1);
if (delta) {
return Math.sign(temp.dot(plane.normal)) * intersect2.angleTo(intersect1);
this.updateJoint(manipulating, manipulating.angle + delta);
}
};
}
// Get the amount to move the prismatic joint based on the mouse move
const getMove = (tg, m1, m2) => {
this.raycaster.ray.copy(toRay);
this.update();
const dist = temp.copy(clickPoint).sub(this.camera.position).length();
}
raycaster.setFromCamera(m1, this.camera);
raycaster.ray.direction.normalize().multiplyScalar(dist);
intersect1.copy(raycaster.ray.origin).add(raycaster.ray.direction);
setGrabbed(grabbed) {
raycaster.setFromCamera(m2, this.camera);
raycaster.ray.direction.normalize().multiplyScalar(dist);
intersect2.copy(raycaster.ray.origin).add(raycaster.ray.direction);
const { hovered, manipulating } = this;
temp.copy(intersect2).sub(intersect1);
if (grabbed) {
plane.normal.copy(tg.axis).transformDirection(tg.parent.matrixWorld).normalize();
if (manipulating !== null || hovered === null) {
return temp.length() * -Math.sign(temp.dot(plane.normal));
return;
}
this.manipulating = hovered;
this.onDragStart(hovered);
} else {
if (this.manipulating === null) {
return;
}
this.onDragEnd(this.manipulating);
this.manipulating = null;
this.update();
}
}
}
class PointerURDFDragControls extends URDFDragControls {
constructor(scene, camera, domElement) {
super(scene);
this.camera = camera;
this.domElement = domElement;
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function updateMouse(e) {
mouse.x = ((e.pageX - domElement.offsetLeft) / domElement.offsetWidth) * 2 - 1;
mouse.y = -((e.pageY - domElement.offsetTop) / domElement.offsetHeight) * 2 + 1;
}
this._mouseDown = e => {
updateMouse(e);
raycaster.setFromCamera(mouse, this.camera);
this.moveRay(raycaster.ray);
this.setGrabbed(true);
};
el.addEventListener('mousedown', e => {
this._mouseMove = e => {
if (this.disableDragging) return;
updateMouse(e);
raycaster.setFromCamera(mouse, this.camera);
this.moveRay(raycaster.ray);
toMouseCoord(e, mouse);
lastMouse.copy(mouse);
};
// get the information on the clicked item
// and set the dragged joint
const target = getCollisions(mouse).shift();
if (target) {
this._mouseUp = e => {
dragging = findNearestJoint(target.object);
updateMouse(e);
raycaster.setFromCamera(mouse, this.camera);
this.moveRay(raycaster.ray);
this.setGrabbed(false);
if (dragging) {
};
clickPoint.copy(target.point);
this.dispatchEvent(new CustomEvent('manipulate-start', { bubbles: true, cancelable: true, detail: dragging.name }));
this.controls.enabled = false;
domElement.addEventListener('mousedown', this._mouseDown);
domElement.addEventListener('mousemove', this._mouseMove);
domElement.addEventListener('mouseup', this._mouseUp);
}
}
}
getRevoluteDelta(joint, startPoint, endPoint) {
}, true);
const { camera, initialGrabPoint } = this;
let hovered = null;
this._mouseMoveFunc = e => {
// set up the plane
tempVector
.copy(joint.axis)
.transformDirection(joint.matrixWorld)
.normalize();
pivotPoint
.set(0, 0, 0)
.applyMatrix4(joint.matrixWorld);
plane
.setFromNormalAndCoplanarPoint(tempVector, pivotPoint);
toMouseCoord(e, mouse);
delta.copy(mouse).sub(lastMouse);
tempVector
.copy(camera.position)
.sub(initialGrabPoint)
.normalize();
// Keep track of the hovered item. If an item is being
// dragged, then it is considered hovered
const wasHovered = hovered;
if (hovered) {
// if looking into the plane of rotation
if (Math.abs(tempVector.dot(plane.normal)) > 0.3) {
hovered = null;
}
return super.getRevoluteDelta(joint, startPoint, endPoint);
if (dragging == null && this.disableDragging === false) {
} else {
const collision = getCollisions(mouse).shift() || null;
const joint = collision && findNearestJoint(collision.object);
if (joint) {
// get the up direction
tempVector.set(0, 1, 0).transformDirection(camera.matrixWorld);
hovered = joint;
// get points projected onto the plane of rotation
plane.projectPoint(startPoint, projectedStartPoint);
plane.projectPoint(endPoint, projectedEndPoint);
}
tempVector.set(0, 0, -1).transformDirection(camera.matrixWorld);
tempVector.cross(plane.normal);
tempVector2.subVectors(endPoint, startPoint);
} else if (dragging) {
return tempVector.dot(tempVector2);
hovered = dragging;
}
}
}
// Highlight the meshes and broadcast events if the hovered item changed
if (hovered !== wasHovered) {
dispose() {
if (wasHovered) {
const { domElement } = this;
domElement.removeEventListener('mousedown', this._mouseDown);
domElement.removeEventListener('mousemove', this._mouseMove);
domElement.removeEventListener('mouseup', this._mouseUp);
highlightLinkGeometry(wasHovered, true);
this.dispatchEvent(new CustomEvent('joint-mouseout', { bubbles: true, cancelable: true, detail: wasHovered.name }));
}
}
}
if (hovered) {
// urdf-manipulator element
// Displays a URDF model that can be manipulated with the mouse
highlightLinkGeometry(hovered, false);
this.dispatchEvent(new CustomEvent('joint-mouseover', { bubbles: true, cancelable: true, detail: hovered.name }));
// Events
// joint-mouseover: Fired when a joint is hovered over
// joint-mouseout: Fired when a joint is no longer hovered over
// manipulate-start: Fires when a joint is manipulated
// manipulate-end: Fires when a joint is done being manipulated
class URDFManipulator extends URDFViewer__default['default'] {
}
static get observedAttributes() {
this.redraw();
return ['highlight-color', ...super.observedAttributes];
}
}
// Apply the manipulation
if (dragging !== null) {
get disableDragging() { return this.hasAttribute('disable-dragging'); }
set disableDragging(val) { val ? this.setAttribute('disable-dragging', !!val) : this.removeAttribute('disable-dragging'); }
let delta = null;
if (dragging.jointType === 'revolute' || dragging.jointType === 'continuous') {
get highlightColor() { return this.getAttribute('highlight-color') || '#FFFFFF'; }
set highlightColor(val) { val ? this.setAttribute('highlight-color', val) : this.removeAttribute('highlight-color'); }
delta = getAngle(dragging, mouse, lastMouse);
constructor(...args) {
} else if (dragging.jointType === 'prismatic') {
super(...args);
delta = getMove(dragging, mouse, lastMouse);
// The highlight material
this.highlightMaterial =
new THREE.MeshPhongMaterial({
shininess: 10,
color: this.highlightColor,
emissive: this.highlightColor,
emissiveIntensity: 0.25,
});
} else {
const isJoint = j => {
// Not supported
return j.isURDFJoint && j.jointType !== 'fixed';
};
// Highlight the link geometry under a joint
const highlightLinkGeometry = (m, revert) => {
const traverse = c => {
// Set or revert the highlight color
if (c.type === 'Mesh') {
if (revert) {
c.material = c.__origMaterial;
delete c.__origMaterial;
} else {
c.__origMaterial = c.material;
c.material = this.highlightMaterial;
}
}
if (delta) {
// Look into the children and stop if the next child is
// another joint
if (c === m || !isJoint(c)) {
this.setJointValue(dragging.name, dragging.angle + delta);
for (let i = 0; i < c.children.length; i++) {
traverse(c.children[i]);
}
}
}
};
lastMouse.copy(mouse);
traverse(m);
};
// Clean up
this._mouseUpFunc = e => {
const el = this.renderer.domElement;
if (dragging) {
const dragControls = new PointerURDFDragControls(this.scene, this.camera, el);
dragControls.onDragStart = joint => {
this.dispatchEvent(new CustomEvent('manipulate-end', { bubbles: true, cancelable: true, detail: dragging.name }));
dragging = null;
this.controls.enabled = true;
this.dispatchEvent(new CustomEvent('manipulate-start', { bubbles: true, cancelable: true, detail: joint.name }));
this.controls.enabled = false;
this.redraw();
}
};
dragControls.onDragEnd = joint => {
this.dispatchEvent(new CustomEvent('manipulate-end', { bubbles: true, cancelable: true, detail: joint.name }));
this.controls.enabled = true;
this.redraw();
};
dragControls.updateJoint = (joint, angle) => {
}
this.setJointValue(joint.name, angle);
connectedCallback() {
};
dragControls.onHover = joint => {
super.connectedCallback();
window.addEventListener('mousemove', this._mouseMoveFunc, true);
window.addEventListener('mouseup', this._mouseUpFunc, true);
highlightLinkGeometry(joint, false);
this.dispatchEvent(new CustomEvent('joint-mouseout', { bubbles: true, cancelable: true, detail: joint.name }));
this.redraw();
};
dragControls.onUnhover = joint => {
highlightLinkGeometry(joint, true);
this.dispatchEvent(new CustomEvent('joint-mouseover', { bubbles: true, cancelable: true, detail: joint.name }));
this.redraw();
};
this.dragControls = dragControls;
}

@@ -375,4 +465,3 @@

super.disconnectedCallback();
window.removeEventListener('mousemove', this._mouseMoveFunc, true);
window.removeEventListener('mouseup', this._mouseUpFunc, true);
this.dragControls.dispose();

@@ -379,0 +468,0 @@ }

@@ -7,3 +7,3 @@ (function (global, factory) {

class URDFCollider extends THREE.Object3D {
class URDFBase extends THREE.Object3D {

@@ -13,5 +13,4 @@ constructor(...args) {

super(...args);
this.isURDFCollider = true;
this.type = 'URDFCollider';
this.urdfNode = null;
this.urdfName = '';

@@ -23,3 +22,5 @@ }

super.copy(source, recursive);
this.urdfNode = source.urdfNode;
this.urdfName = source.urdfName;

@@ -32,3 +33,3 @@ return this;

class URDFVisual extends THREE.Object3D {
class URDFCollider extends URDFBase {

@@ -38,15 +39,17 @@ constructor(...args) {

super(...args);
this.isURDFVisual = true;
this.type = 'URDFVisual';
this.urdfNode = null;
this.isURDFCollider = true;
this.type = 'URDFCollider';
}
copy(source, recursive) {
}
super.copy(source, recursive);
this.urdfNode = source.urdfNode;
class URDFVisual extends URDFBase {
return this;
constructor(...args) {
super(...args);
this.isURDFVisual = true;
this.type = 'URDFVisual';
}

@@ -56,3 +59,3 @@

class URDFLink extends THREE.Object3D {
class URDFLink extends URDFBase {

@@ -64,18 +67,8 @@ constructor(...args) {

this.type = 'URDFLink';
this.urdfNode = null;
}
copy(source, recursive) {
super.copy(source, recursive);
this.urdfNode = source.urdfNode;
return this;
}
}
class URDFJoint extends THREE.Object3D {
class URDFJoint extends URDFBase {

@@ -130,3 +123,2 @@ get jointType() {

this.urdfNode = null;
this.jointValue = null;

@@ -148,3 +140,2 @@ this.jointType = 'fixed';

this.urdfNode = source.urdfNode;
this.jointType = source.jointType;

@@ -189,3 +180,3 @@ this.axis = source.axis ? source.axis.clone() : null;

if (angle == null) return false;
if (angle === this.angle) return false;
if (angle === this.jointValue[0]) return false;

@@ -199,6 +190,5 @@ if (!this.ignoreLimits && this.jointType === 'revolute') {

// FromAxisAngle seems to rotate the opposite of the
// expected angle for URDF, so negate it here
const delta = new THREE.Quaternion().setFromAxisAngle(this.axis, angle);
this.quaternion.multiplyQuaternions(this.origQuaternion, delta);
this.quaternion
.setFromAxisAngle(this.axis, angle)
.premultiply(this.origQuaternion);

@@ -223,3 +213,3 @@ if (this.jointValue[0] !== angle) {

if (pos == null) return false;
if (pos === this.angle) return false;
if (pos === this.jointValue[0]) return false;

@@ -296,23 +286,23 @@ if (!this.ignoreLimits) {

if (c.isURDFJoint && c.name in source.joints) {
if (c.isURDFJoint && c.urdfName in source.joints) {
this.joints[c.name] = c;
this.joints[c.urdfName] = c;
}
if (c.isURDFLink && c.name in source.links) {
if (c.isURDFLink && c.urdfName in source.links) {
this.links[c.name] = c;
this.links[c.urdfName] = c;
}
if (c.isURDFCollider && c.name in source.colliders) {
if (c.isURDFCollider && c.urdfName in source.colliders) {
this.colliders[c.name] = c;
this.colliders[c.urdfName] = c;
}
if (c.isURDFVisual && c.name in source.visual) {
if (c.isURDFVisual && c.urdfName in source.visual) {
this.visual[c.name] = c;
this.visual[c.urdfName] = c;

@@ -466,8 +456,16 @@ }

if (onProgress) {
if (res.ok) {
onProgress(null);
if (onProgress) {
onProgress(null);
}
return res.text();
} else {
throw new Error(`URDFLoader: Failed to load url '${ urdfPath }' with error code ${ res.status } : ${ res.statusText }.`);
}
return res.text();

@@ -545,2 +543,6 @@ })

} else if (packages instanceof Function) {
return packages(targetPkg) + '/' + relPath;
} else if (typeof packages === 'object') {

@@ -652,2 +654,3 @@

obj.name = joint.getAttribute('name');
obj.urdfName = obj.name;
obj.jointType = jointType;

@@ -718,2 +721,3 @@

target.name = link.getAttribute('name');
target.urdfName = target.name;
target.urdfNode = link;

@@ -733,2 +737,3 @@

v.name = name;
v.urdfName = name;
visualMap[name] = v;

@@ -754,2 +759,3 @@

c.name = name;
c.urdfName = name;
colliderMap[name] = c;

@@ -756,0 +762,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc