@woosh/meep-engine 2.78.0 → 2.79.0
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/build/meep.cjs +87 -63
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +87 -63
- package/package.json +1 -1
- package/src/core/{graph → geom/3d/topology}/build_face_graph_from_mesh.js +5 -5
- package/src/core/geom/Quaternion.js +1 -1
- package/src/core/geom/vec3/v3_angle_between.js +15 -4
- package/src/core/geom/vec3/{v3_computeOffsetVector.js → v3_displace_in_direction.js} +11 -2
- package/src/core/graph/Edge.js +10 -22
- package/src/core/graph/Edge.spec.js +35 -0
- package/src/core/graph/MultiNode.js +6 -7
- package/src/core/graph/v2/Graph.js +20 -8
- package/src/core/graph/v2/NodeContainer.js +1 -0
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +2 -2
- package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +2 -2
- package/src/engine/ecs/transform-attachment/TransformAttachment.js +2 -1
- package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +45 -33
- package/src/core/graph/EdgeDirection.js +0 -11
- package/src/core/primitives/strings/prefixTree/PrefixTree.js +0 -225
- package/src/core/primitives/strings/prefixTree/PrefixTree.spec.js +0 -39
- package/src/core/primitives/strings/prefixTree/PrefixTreeLeaf.js +0 -25
- package/src/core/primitives/strings/prefixTree/PrefixTreeNode.js +0 -16
package/build/meep.module.js
CHANGED
|
@@ -1978,10 +1978,15 @@ function v3_length(x, y, z) {
|
|
|
1978
1978
|
* @param {number} z1
|
|
1979
1979
|
* @returns {number}
|
|
1980
1980
|
*/
|
|
1981
|
-
function v3_angle_between(
|
|
1981
|
+
function v3_angle_between(
|
|
1982
|
+
x0, y0, z0,
|
|
1983
|
+
x1, y1, z1
|
|
1984
|
+
) {
|
|
1985
|
+
|
|
1982
1986
|
const theta = v3_angle_cos_between(x0, y0, z0, x1, y1, z1);
|
|
1983
1987
|
|
|
1984
1988
|
return Math.acos(theta);
|
|
1989
|
+
|
|
1985
1990
|
}
|
|
1986
1991
|
|
|
1987
1992
|
/**
|
|
@@ -1992,9 +1997,13 @@ function v3_angle_between(x0, y0, z0, x1, y1, z1) {
|
|
|
1992
1997
|
* @param {number} x1
|
|
1993
1998
|
* @param {number} y1
|
|
1994
1999
|
* @param {number} z1
|
|
1995
|
-
* @returns {number}
|
|
2000
|
+
* @returns {number} value between -1 and 1, cosine of the angle between vectors
|
|
1996
2001
|
*/
|
|
1997
|
-
function v3_angle_cos_between(
|
|
2002
|
+
function v3_angle_cos_between(
|
|
2003
|
+
x0, y0, z0,
|
|
2004
|
+
x1, y1, z1
|
|
2005
|
+
) {
|
|
2006
|
+
|
|
1998
2007
|
const d = v3_dot(x0, y0, z0, x1, y1, z1);
|
|
1999
2008
|
|
|
2000
2009
|
const magnitude_0 = v3_length(x0, y0, z0);
|
|
@@ -2004,10 +2013,12 @@ function v3_angle_cos_between(x0, y0, z0, x1, y1, z1){
|
|
|
2004
2013
|
|
|
2005
2014
|
if (l === 0) {
|
|
2006
2015
|
// collective magnitude is 0, provide arbitrary angle
|
|
2016
|
+
// avoid division by 0
|
|
2007
2017
|
return 0;
|
|
2008
2018
|
}
|
|
2009
2019
|
|
|
2010
2020
|
return clamp$1(d / l, -1, 1);
|
|
2021
|
+
|
|
2011
2022
|
}
|
|
2012
2023
|
|
|
2013
2024
|
/**
|
|
@@ -4706,7 +4717,7 @@ let Quaternion$1 = class Quaternion {
|
|
|
4706
4717
|
* @param {Quaternion} result
|
|
4707
4718
|
* @param {Quaternion} from
|
|
4708
4719
|
* @param {Quaternion} to
|
|
4709
|
-
* @param {number} max_delta
|
|
4720
|
+
* @param {number} max_delta in radians
|
|
4710
4721
|
*/
|
|
4711
4722
|
static rotateTowards(result, from, to, max_delta) {
|
|
4712
4723
|
|
|
@@ -70583,10 +70594,19 @@ class Edge {
|
|
|
70583
70594
|
return this.first === node || this.second === node;
|
|
70584
70595
|
}
|
|
70585
70596
|
|
|
70597
|
+
/**
|
|
70598
|
+
*
|
|
70599
|
+
* @param {N} source
|
|
70600
|
+
* @param {N} target
|
|
70601
|
+
* @returns {boolean} True iff the edge contains both source and target and allows transition from source to target
|
|
70602
|
+
*/
|
|
70586
70603
|
validateTransition(source, target) {
|
|
70587
70604
|
const a = this.first;
|
|
70588
70605
|
const b = this.second;
|
|
70589
|
-
|
|
70606
|
+
|
|
70607
|
+
return (a === source && b === target && this.traversableForward())
|
|
70608
|
+
|| (b === source && a === target && this.traversableBackward())
|
|
70609
|
+
;
|
|
70590
70610
|
}
|
|
70591
70611
|
|
|
70592
70612
|
/**
|
|
@@ -70634,16 +70654,6 @@ class Edge {
|
|
|
70634
70654
|
|| (this.second === node && this.direction === EdgeDirectionType.Backward)
|
|
70635
70655
|
}
|
|
70636
70656
|
|
|
70637
|
-
/**
|
|
70638
|
-
* @deprecated
|
|
70639
|
-
* @returns {number}
|
|
70640
|
-
*/
|
|
70641
|
-
angle() {
|
|
70642
|
-
|
|
70643
|
-
const delta = this.second.clone().sub(this.first);
|
|
70644
|
-
return Math.atan2(delta.y, delta.x);
|
|
70645
|
-
}
|
|
70646
|
-
|
|
70647
70657
|
/**
|
|
70648
70658
|
*
|
|
70649
70659
|
* @returns {N[]}
|
|
@@ -70652,15 +70662,6 @@ class Edge {
|
|
|
70652
70662
|
return [this.first, this.second];
|
|
70653
70663
|
}
|
|
70654
70664
|
|
|
70655
|
-
|
|
70656
|
-
/**
|
|
70657
|
-
* @deprecated
|
|
70658
|
-
* @returns {number}
|
|
70659
|
-
*/
|
|
70660
|
-
get length() {
|
|
70661
|
-
|
|
70662
|
-
return this.first.distanceTo(this.second);
|
|
70663
|
-
}
|
|
70664
70665
|
}
|
|
70665
70666
|
|
|
70666
70667
|
/**
|
|
@@ -70691,6 +70692,7 @@ class NodeContainer {
|
|
|
70691
70692
|
/**
|
|
70692
70693
|
*
|
|
70693
70694
|
* @type {Map<N,number>}
|
|
70695
|
+
* Maps neighbour node to number of edges to that node from this one
|
|
70694
70696
|
* @private
|
|
70695
70697
|
*/
|
|
70696
70698
|
__neighbors = new Map();
|
|
@@ -71084,6 +71086,7 @@ class Graph {
|
|
|
71084
71086
|
/**
|
|
71085
71087
|
*
|
|
71086
71088
|
* @param {N} node
|
|
71089
|
+
* @returns {boolean}
|
|
71087
71090
|
*/
|
|
71088
71091
|
removeNode(node) {
|
|
71089
71092
|
|
|
@@ -71157,7 +71160,7 @@ class Graph {
|
|
|
71157
71160
|
}
|
|
71158
71161
|
|
|
71159
71162
|
/**
|
|
71160
|
-
*
|
|
71163
|
+
* Node degree is the number of attached edges
|
|
71161
71164
|
* @param {N} node
|
|
71162
71165
|
* @return {number}
|
|
71163
71166
|
*/
|
|
@@ -71199,13 +71202,18 @@ class Graph {
|
|
|
71199
71202
|
*
|
|
71200
71203
|
* @param {N} source
|
|
71201
71204
|
* @param {N} target
|
|
71202
|
-
* @param {EdgeDirectionType} [
|
|
71205
|
+
* @param {EdgeDirectionType} [direction] Undirected by default
|
|
71203
71206
|
* @returns {Edge<N>}
|
|
71204
71207
|
*/
|
|
71205
|
-
createEdge(
|
|
71208
|
+
createEdge(
|
|
71209
|
+
source,
|
|
71210
|
+
target,
|
|
71211
|
+
direction = EdgeDirectionType.Undirected
|
|
71212
|
+
) {
|
|
71213
|
+
|
|
71206
71214
|
const edge = new Edge(source, target);
|
|
71207
71215
|
|
|
71208
|
-
edge.direction =
|
|
71216
|
+
edge.direction = direction;
|
|
71209
71217
|
|
|
71210
71218
|
this.addEdge(edge);
|
|
71211
71219
|
|
|
@@ -71213,9 +71221,10 @@ class Graph {
|
|
|
71213
71221
|
}
|
|
71214
71222
|
|
|
71215
71223
|
/**
|
|
71216
|
-
*
|
|
71224
|
+
* Both nodes that the edge is attached to must be present
|
|
71217
71225
|
* @param {Edge<N>} edge
|
|
71218
|
-
* @returns {boolean}
|
|
71226
|
+
* @returns {boolean} true if edge was added, false if edge was already present
|
|
71227
|
+
* @throws if one or both nodes are not contained in the graph
|
|
71219
71228
|
*/
|
|
71220
71229
|
addEdge(edge) {
|
|
71221
71230
|
if (this.hasEdge(edge)) {
|
|
@@ -71417,10 +71426,10 @@ class Graph {
|
|
|
71417
71426
|
}
|
|
71418
71427
|
|
|
71419
71428
|
/**
|
|
71420
|
-
*
|
|
71429
|
+
* Find a path through the graph
|
|
71421
71430
|
* @param {N} start
|
|
71422
71431
|
* @param {N} goal
|
|
71423
|
-
* @returns {null|N[]}
|
|
71432
|
+
* @returns {null|N[]} null if no path exists
|
|
71424
71433
|
*/
|
|
71425
71434
|
findPath(start, goal) {
|
|
71426
71435
|
const start_node_container = this.__nodes.get(start);
|
|
@@ -71460,6 +71469,7 @@ class Graph {
|
|
|
71460
71469
|
const b = edge.second;
|
|
71461
71470
|
|
|
71462
71471
|
let other = null;
|
|
71472
|
+
|
|
71463
71473
|
if (a === current_node && (edge.direction === EdgeDirectionType.Forward || edge.direction === EdgeDirectionType.Undirected)) {
|
|
71464
71474
|
other = b;
|
|
71465
71475
|
} else if (b === current_node && (edge.direction === EdgeDirectionType.Backward || edge.direction === EdgeDirectionType.Undirected)) {
|
|
@@ -71488,6 +71498,9 @@ class Graph {
|
|
|
71488
71498
|
return null;
|
|
71489
71499
|
}
|
|
71490
71500
|
|
|
71501
|
+
/**
|
|
71502
|
+
* Remove all data from the graph, resetting it to empty state
|
|
71503
|
+
*/
|
|
71491
71504
|
clear() {
|
|
71492
71505
|
this.__nodes.clear();
|
|
71493
71506
|
this.__edges.clear();
|
|
@@ -72956,6 +72969,7 @@ class TransformAttachment {
|
|
|
72956
72969
|
|
|
72957
72970
|
/**
|
|
72958
72971
|
* transform relative to the attachment target
|
|
72972
|
+
* Think of it as "local transform"
|
|
72959
72973
|
* @type {Transform}
|
|
72960
72974
|
*/
|
|
72961
72975
|
transform = new Transform();
|
|
@@ -73569,7 +73583,10 @@ class UpdateContext {
|
|
|
73569
73583
|
}
|
|
73570
73584
|
|
|
73571
73585
|
update() {
|
|
73572
|
-
this.transform.multiplyTransforms(
|
|
73586
|
+
this.transform.multiplyTransforms(
|
|
73587
|
+
this.parent_transform,
|
|
73588
|
+
this.attachment.transform
|
|
73589
|
+
);
|
|
73573
73590
|
}
|
|
73574
73591
|
|
|
73575
73592
|
/**
|
|
@@ -73592,51 +73609,51 @@ class UpdateContext {
|
|
|
73592
73609
|
link() {
|
|
73593
73610
|
const t_parent = this.parent_transform;
|
|
73594
73611
|
|
|
73595
|
-
t_parent.
|
|
73596
|
-
t_parent.rotation.onChanged.add(this.update, this);
|
|
73597
|
-
t_parent.scale.onChanged.add(this.update, this);
|
|
73612
|
+
t_parent.subscribe(this.update, this);
|
|
73598
73613
|
|
|
73599
73614
|
const t_attachment = this.attachment.transform;
|
|
73600
|
-
|
|
73601
|
-
t_attachment.
|
|
73602
|
-
t_attachment.scale.onChanged.add(this.update,this);
|
|
73615
|
+
|
|
73616
|
+
t_attachment.subscribe(this.update, this);
|
|
73603
73617
|
}
|
|
73604
73618
|
|
|
73605
73619
|
unlink() {
|
|
73606
73620
|
const transform = this.parent_transform;
|
|
73607
73621
|
|
|
73608
|
-
transform.
|
|
73609
|
-
transform.rotation.onChanged.remove(this.update, this);
|
|
73610
|
-
transform.scale.onChanged.remove(this.update, this);
|
|
73622
|
+
transform.unsubscribe(this.update, this);
|
|
73611
73623
|
|
|
73612
73624
|
const t_attachment = this.attachment.transform;
|
|
73613
|
-
|
|
73614
|
-
t_attachment.
|
|
73615
|
-
t_attachment.scale.onChanged.remove(this.update,this);
|
|
73625
|
+
|
|
73626
|
+
t_attachment.unsubscribe(this.update, this);
|
|
73616
73627
|
}
|
|
73617
73628
|
}
|
|
73618
73629
|
|
|
73619
73630
|
class TransformAttachmentSystem extends System {
|
|
73631
|
+
|
|
73632
|
+
/**
|
|
73633
|
+
*
|
|
73634
|
+
* @type {UpdateContext[]}
|
|
73635
|
+
* @private
|
|
73636
|
+
*/
|
|
73637
|
+
__contexts = [];
|
|
73638
|
+
|
|
73639
|
+
/**
|
|
73640
|
+
*
|
|
73641
|
+
* @type {UpdateContext[]}
|
|
73642
|
+
* @private
|
|
73643
|
+
*/
|
|
73644
|
+
__queue = [];
|
|
73645
|
+
__queue_size = 0;
|
|
73646
|
+
__queue_cursor = 0;
|
|
73647
|
+
|
|
73620
73648
|
constructor() {
|
|
73621
73649
|
super();
|
|
73622
73650
|
|
|
73623
73651
|
this.dependencies = [TransformAttachment, Transform];
|
|
73624
73652
|
|
|
73625
|
-
|
|
73626
|
-
|
|
73627
|
-
|
|
73628
|
-
|
|
73629
|
-
*/
|
|
73630
|
-
this.__contexts = [];
|
|
73631
|
-
|
|
73632
|
-
/**
|
|
73633
|
-
*
|
|
73634
|
-
* @type {UpdateContext[]}
|
|
73635
|
-
* @private
|
|
73636
|
-
*/
|
|
73637
|
-
this.__queue = [];
|
|
73638
|
-
this.__queue_size = 0;
|
|
73639
|
-
this.__queue_cursor = 0;
|
|
73653
|
+
this.components_used = [
|
|
73654
|
+
ResourceAccessSpecification.from(TransformAttachment, ResourceAccessKind.Read),
|
|
73655
|
+
ResourceAccessSpecification.from(Transform, ResourceAccessKind.Read | ResourceAccessKind.Write),
|
|
73656
|
+
];
|
|
73640
73657
|
}
|
|
73641
73658
|
|
|
73642
73659
|
/**
|
|
@@ -73664,6 +73681,12 @@ class TransformAttachmentSystem extends System {
|
|
|
73664
73681
|
this.__queue[this.__queue_size++] = ctx;
|
|
73665
73682
|
}
|
|
73666
73683
|
|
|
73684
|
+
/**
|
|
73685
|
+
*
|
|
73686
|
+
* @param {number} entity
|
|
73687
|
+
* @returns {boolean}
|
|
73688
|
+
* @private
|
|
73689
|
+
*/
|
|
73667
73690
|
__dequeue_entity(entity) {
|
|
73668
73691
|
for (let i = 0; i < this.__queue_size; i++) {
|
|
73669
73692
|
const ctx = this.__queue[i];
|
|
@@ -73692,9 +73715,7 @@ class TransformAttachmentSystem extends System {
|
|
|
73692
73715
|
ctx.entity = entity;
|
|
73693
73716
|
|
|
73694
73717
|
|
|
73695
|
-
|
|
73696
|
-
|
|
73697
|
-
ctx.ecd = ecd;
|
|
73718
|
+
ctx.ecd = this.entityManager.dataset;
|
|
73698
73719
|
|
|
73699
73720
|
if (ctx.bind_parent()) {
|
|
73700
73721
|
this.__finalize_link(ctx);
|
|
@@ -73729,12 +73750,14 @@ class TransformAttachmentSystem extends System {
|
|
|
73729
73750
|
|
|
73730
73751
|
update(timeDelta) {
|
|
73731
73752
|
const step_count = min2(this.__queue_size, QUEUE_ITERATION_COUNT);
|
|
73753
|
+
|
|
73732
73754
|
for (let i = 0; i < step_count; i++) {
|
|
73733
73755
|
const index = this.__queue_cursor % this.__queue_size;
|
|
73734
73756
|
|
|
73735
73757
|
const ctx = this.__queue[index];
|
|
73736
73758
|
|
|
73737
73759
|
if (ctx.bind_parent()) {
|
|
73760
|
+
// parent obtained
|
|
73738
73761
|
this.__finalize_link(ctx);
|
|
73739
73762
|
|
|
73740
73763
|
this.__queue.splice(index, 1);
|
|
@@ -73744,6 +73767,7 @@ class TransformAttachmentSystem extends System {
|
|
|
73744
73767
|
this.__queue_cursor++;
|
|
73745
73768
|
}
|
|
73746
73769
|
}
|
|
73770
|
+
|
|
73747
73771
|
}
|
|
73748
73772
|
}
|
|
73749
73773
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { MultiNode } from "
|
|
3
|
-
import {
|
|
4
|
-
import { WeightedEdge } from "
|
|
5
|
-
import {
|
|
1
|
+
import { graph_compute_disconnected_clusters } from "../../../graph/graph_compute_disconnected_clusters.js";
|
|
2
|
+
import { MultiNode } from "../../../graph/MultiNode.js";
|
|
3
|
+
import { Graph } from "../../../graph/v2/Graph.js";
|
|
4
|
+
import { WeightedEdge } from "../../../graph/WeightedEdge.js";
|
|
5
|
+
import { compute_face_connection_weight } from "./util/compute_face_connection_weight.js";
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -1546,7 +1546,7 @@ class Quaternion {
|
|
|
1546
1546
|
* @param {Quaternion} result
|
|
1547
1547
|
* @param {Quaternion} from
|
|
1548
1548
|
* @param {Quaternion} to
|
|
1549
|
-
* @param {number} max_delta
|
|
1549
|
+
* @param {number} max_delta in radians
|
|
1550
1550
|
*/
|
|
1551
1551
|
static rotateTowards(result, from, to, max_delta) {
|
|
1552
1552
|
assert.isNumber(max_delta, 'max_delta');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { clamp } from "../../math/clamp.js";
|
|
1
2
|
import { v3_dot } from "./v3_dot.js";
|
|
2
3
|
import { v3_length } from "./v3_length.js";
|
|
3
|
-
import { clamp } from "../../math/clamp.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
*
|
|
@@ -12,10 +12,15 @@ import { clamp } from "../../math/clamp.js";
|
|
|
12
12
|
* @param {number} z1
|
|
13
13
|
* @returns {number}
|
|
14
14
|
*/
|
|
15
|
-
export function v3_angle_between(
|
|
15
|
+
export function v3_angle_between(
|
|
16
|
+
x0, y0, z0,
|
|
17
|
+
x1, y1, z1
|
|
18
|
+
) {
|
|
19
|
+
|
|
16
20
|
const theta = v3_angle_cos_between(x0, y0, z0, x1, y1, z1);
|
|
17
21
|
|
|
18
22
|
return Math.acos(theta);
|
|
23
|
+
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
/**
|
|
@@ -26,9 +31,13 @@ export function v3_angle_between(x0, y0, z0, x1, y1, z1) {
|
|
|
26
31
|
* @param {number} x1
|
|
27
32
|
* @param {number} y1
|
|
28
33
|
* @param {number} z1
|
|
29
|
-
* @returns {number}
|
|
34
|
+
* @returns {number} value between -1 and 1, cosine of the angle between vectors
|
|
30
35
|
*/
|
|
31
|
-
export function v3_angle_cos_between(
|
|
36
|
+
export function v3_angle_cos_between(
|
|
37
|
+
x0, y0, z0,
|
|
38
|
+
x1, y1, z1
|
|
39
|
+
) {
|
|
40
|
+
|
|
32
41
|
const d = v3_dot(x0, y0, z0, x1, y1, z1);
|
|
33
42
|
|
|
34
43
|
const magnitude_0 = v3_length(x0, y0, z0);
|
|
@@ -38,10 +47,12 @@ export function v3_angle_cos_between(x0, y0, z0, x1, y1, z1){
|
|
|
38
47
|
|
|
39
48
|
if (l === 0) {
|
|
40
49
|
// collective magnitude is 0, provide arbitrary angle
|
|
50
|
+
// avoid division by 0
|
|
41
51
|
return 0;
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
return clamp(d / l, -1, 1);
|
|
55
|
+
|
|
45
56
|
}
|
|
46
57
|
|
|
47
58
|
/**
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* @param {number} directionX
|
|
9
9
|
* @param {number} directionY
|
|
10
10
|
* @param {number} directionZ
|
|
11
|
+
* @returns {boolean} true if displaced successfully, false if direction had 0 magnitude
|
|
11
12
|
*/
|
|
12
|
-
export function
|
|
13
|
+
export function v3_displace_in_direction(
|
|
13
14
|
result,
|
|
14
15
|
distance,
|
|
15
16
|
sourceX, sourceY, sourceZ,
|
|
@@ -17,13 +18,19 @@ export function v3_computeOffsetVector(
|
|
|
17
18
|
) {
|
|
18
19
|
if (distance === 0) {
|
|
19
20
|
result.set(sourceX, sourceY, sourceZ);
|
|
20
|
-
return;
|
|
21
|
+
return true;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
//scale direction to have length equal to distance
|
|
24
25
|
|
|
25
26
|
const directionLength = Math.sqrt(directionX * directionX + directionY * directionY + directionZ * directionZ);
|
|
26
27
|
|
|
28
|
+
if(directionLength === 0){
|
|
29
|
+
// direction vector is zero length, avoid division by zero, clamp to source instead
|
|
30
|
+
result.set(sourceX, sourceY, sourceZ);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
27
34
|
const m = distance / directionLength;
|
|
28
35
|
|
|
29
36
|
const x = sourceX + directionX * m;
|
|
@@ -31,4 +38,6 @@ export function v3_computeOffsetVector(
|
|
|
31
38
|
const z = sourceZ + directionZ * m;
|
|
32
39
|
|
|
33
40
|
result.set(x, y, z);
|
|
41
|
+
|
|
42
|
+
return true;
|
|
34
43
|
}
|
package/src/core/graph/Edge.js
CHANGED
|
@@ -55,10 +55,19 @@ export class Edge {
|
|
|
55
55
|
return this.first === node || this.second === node;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @param {N} source
|
|
61
|
+
* @param {N} target
|
|
62
|
+
* @returns {boolean} True iff the edge contains both source and target and allows transition from source to target
|
|
63
|
+
*/
|
|
58
64
|
validateTransition(source, target) {
|
|
59
65
|
const a = this.first;
|
|
60
66
|
const b = this.second;
|
|
61
|
-
|
|
67
|
+
|
|
68
|
+
return (a === source && b === target && this.traversableForward())
|
|
69
|
+
|| (b === source && a === target && this.traversableBackward())
|
|
70
|
+
;
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
/**
|
|
@@ -106,17 +115,6 @@ export class Edge {
|
|
|
106
115
|
|| (this.second === node && this.direction === EdgeDirectionType.Backward)
|
|
107
116
|
}
|
|
108
117
|
|
|
109
|
-
/**
|
|
110
|
-
* @deprecated
|
|
111
|
-
* @returns {number}
|
|
112
|
-
*/
|
|
113
|
-
angle() {
|
|
114
|
-
console.error('method is deprecated, do not use');
|
|
115
|
-
|
|
116
|
-
const delta = this.second.clone().sub(this.first);
|
|
117
|
-
return Math.atan2(delta.y, delta.x);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
118
|
/**
|
|
121
119
|
*
|
|
122
120
|
* @returns {N[]}
|
|
@@ -125,16 +123,6 @@ export class Edge {
|
|
|
125
123
|
return [this.first, this.second];
|
|
126
124
|
}
|
|
127
125
|
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* @deprecated
|
|
131
|
-
* @returns {number}
|
|
132
|
-
*/
|
|
133
|
-
get length() {
|
|
134
|
-
console.error('method is deprecated, do not use');
|
|
135
|
-
|
|
136
|
-
return this.first.distanceTo(this.second);
|
|
137
|
-
}
|
|
138
126
|
}
|
|
139
127
|
|
|
140
128
|
/**
|
|
@@ -48,3 +48,38 @@ test('other', () => {
|
|
|
48
48
|
expect(edge.other(3)).toBe(7);
|
|
49
49
|
expect(edge.other(7)).toBe(3);
|
|
50
50
|
});
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
test("isDirectedTowards", () => {
|
|
54
|
+
const e = new Edge(1, 3);
|
|
55
|
+
|
|
56
|
+
e.direction = EdgeDirectionType.Forward;
|
|
57
|
+
|
|
58
|
+
expect(e.isDirectedTowards(3)).toBe(true);
|
|
59
|
+
expect(e.isDirectedTowards(1)).toBe(false);
|
|
60
|
+
|
|
61
|
+
e.direction = EdgeDirectionType.Backward;
|
|
62
|
+
|
|
63
|
+
expect(e.isDirectedTowards(3)).toBe(false);
|
|
64
|
+
expect(e.isDirectedTowards(1)).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("isDirectedAwayFrom", () => {
|
|
68
|
+
const e = new Edge(1, 3);
|
|
69
|
+
|
|
70
|
+
e.direction = EdgeDirectionType.Forward;
|
|
71
|
+
|
|
72
|
+
expect(e.isDirectedAwayFrom(3)).toBe(false);
|
|
73
|
+
expect(e.isDirectedAwayFrom(1)).toBe(true);
|
|
74
|
+
|
|
75
|
+
e.direction = EdgeDirectionType.Backward;
|
|
76
|
+
|
|
77
|
+
expect(e.isDirectedAwayFrom(3)).toBe(true);
|
|
78
|
+
expect(e.isDirectedAwayFrom(1)).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("nodes accessor", () => {
|
|
82
|
+
const e = new Edge(1, 3);
|
|
83
|
+
|
|
84
|
+
expect(e.nodes).toEqual([1, 3]);
|
|
85
|
+
});
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* A grouping node, intended mainly for meta-graphs, or hierarchical graphs
|
|
2
3
|
* @template T
|
|
3
4
|
*/
|
|
4
5
|
export class MultiNode {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
this.source_nodes = [];
|
|
11
|
-
}
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @type {T[]}
|
|
9
|
+
*/
|
|
10
|
+
source_nodes = [];
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
*
|
|
@@ -92,6 +92,7 @@ export class Graph {
|
|
|
92
92
|
/**
|
|
93
93
|
*
|
|
94
94
|
* @param {N} node
|
|
95
|
+
* @returns {boolean}
|
|
95
96
|
*/
|
|
96
97
|
removeNode(node) {
|
|
97
98
|
|
|
@@ -165,7 +166,7 @@ export class Graph {
|
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
/**
|
|
168
|
-
*
|
|
169
|
+
* Node degree is the number of attached edges
|
|
169
170
|
* @param {N} node
|
|
170
171
|
* @return {number}
|
|
171
172
|
*/
|
|
@@ -207,13 +208,19 @@ export class Graph {
|
|
|
207
208
|
*
|
|
208
209
|
* @param {N} source
|
|
209
210
|
* @param {N} target
|
|
210
|
-
* @param {EdgeDirectionType} [
|
|
211
|
+
* @param {EdgeDirectionType} [direction] Undirected by default
|
|
211
212
|
* @returns {Edge<N>}
|
|
212
213
|
*/
|
|
213
|
-
createEdge(
|
|
214
|
+
createEdge(
|
|
215
|
+
source,
|
|
216
|
+
target,
|
|
217
|
+
direction = EdgeDirectionType.Undirected
|
|
218
|
+
) {
|
|
219
|
+
assert.enum(direction, EdgeDirectionType, 'direction');
|
|
220
|
+
|
|
214
221
|
const edge = new Edge(source, target);
|
|
215
222
|
|
|
216
|
-
edge.direction =
|
|
223
|
+
edge.direction = direction;
|
|
217
224
|
|
|
218
225
|
this.addEdge(edge);
|
|
219
226
|
|
|
@@ -221,9 +228,10 @@ export class Graph {
|
|
|
221
228
|
}
|
|
222
229
|
|
|
223
230
|
/**
|
|
224
|
-
*
|
|
231
|
+
* Both nodes that the edge is attached to must be present
|
|
225
232
|
* @param {Edge<N>} edge
|
|
226
|
-
* @returns {boolean}
|
|
233
|
+
* @returns {boolean} true if edge was added, false if edge was already present
|
|
234
|
+
* @throws if one or both nodes are not contained in the graph
|
|
227
235
|
*/
|
|
228
236
|
addEdge(edge) {
|
|
229
237
|
if (this.hasEdge(edge)) {
|
|
@@ -431,10 +439,10 @@ export class Graph {
|
|
|
431
439
|
}
|
|
432
440
|
|
|
433
441
|
/**
|
|
434
|
-
*
|
|
442
|
+
* Find a path through the graph
|
|
435
443
|
* @param {N} start
|
|
436
444
|
* @param {N} goal
|
|
437
|
-
* @returns {null|N[]}
|
|
445
|
+
* @returns {null|N[]} null if no path exists
|
|
438
446
|
*/
|
|
439
447
|
findPath(start, goal) {
|
|
440
448
|
const start_node_container = this.__nodes.get(start);
|
|
@@ -474,6 +482,7 @@ export class Graph {
|
|
|
474
482
|
const b = edge.second;
|
|
475
483
|
|
|
476
484
|
let other = null;
|
|
485
|
+
|
|
477
486
|
if (a === current_node && (edge.direction === EdgeDirectionType.Forward || edge.direction === EdgeDirectionType.Undirected)) {
|
|
478
487
|
other = b;
|
|
479
488
|
} else if (b === current_node && (edge.direction === EdgeDirectionType.Backward || edge.direction === EdgeDirectionType.Undirected)) {
|
|
@@ -502,6 +511,9 @@ export class Graph {
|
|
|
502
511
|
return null;
|
|
503
512
|
}
|
|
504
513
|
|
|
514
|
+
/**
|
|
515
|
+
* Remove all data from the graph, resetting it to empty state
|
|
516
|
+
*/
|
|
505
517
|
clear() {
|
|
506
518
|
this.__nodes.clear();
|
|
507
519
|
this.__edges.clear();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SurfacePoint3 } from "../../../core/geom/3d/SurfacePoint3.js";
|
|
2
2
|
import Quaternion from "../../../core/geom/Quaternion.js";
|
|
3
|
-
import {
|
|
3
|
+
import { v3_displace_in_direction } from "../../../core/geom/vec3/v3_displace_in_direction.js";
|
|
4
4
|
import { v3_dot } from "../../../core/geom/vec3/v3_dot.js";
|
|
5
5
|
import { v3_length } from "../../../core/geom/vec3/v3_length.js";
|
|
6
6
|
import Vector3 from "../../../core/geom/Vector3.js";
|
|
@@ -116,7 +116,7 @@ export class OneBoneSurfaceAlignmentSolver extends IKSolver {
|
|
|
116
116
|
|
|
117
117
|
const targetOffsetDistance = constraint.offset * bone_scale;
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
v3_displace_in_direction(
|
|
120
120
|
targetPosition,
|
|
121
121
|
targetOffsetDistance,
|
|
122
122
|
contactPosition.x, contactPosition.y, contactPosition.z,
|